Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Создание приложений универсальной платформы Windows (UWP) с плавной анимацией, высокой скоростью кадров и высокопроизводительной записью и воспроизведением мультимедиа.
Сделать анимацию гладкой
Ключевым аспектом приложений UWP является плавное взаимодействие. Это включает в себя сенсорные манипуляции, которые "прилипают к пальцу", гладкие переходы и анимации, а также небольшие движения, которые обеспечивают обратную связь с входными данными. В платформе XAML существует поток, называемый потоком композиции, предназначенным для композиции и анимации визуальных элементов приложения. Так как поток композиции отделен от потока пользовательского интерфейса (потока, выполняющего платформу и код разработчика), приложения могут достичь согласованной частоты кадров и плавной анимации независимо от сложных параметров макета или расширенных вычислений. В этом разделе показано, как использовать поток композиции для обеспечения плавности анимации приложения. Дополнительные сведения об анимациях см. в обзоре анимаций. Дополнительные сведения о повышении скорости реагирования приложения при выполнении интенсивных вычислений см. в статье Сохранение быстродействующегопотока пользовательского интерфейса.
Использование независимых анимаций вместо зависимых анимаций
Независимые анимации можно вычислить с начала до конца на этапе создания, так как изменения анимируемого свойства не влияют на остальные объекты в сцене. Поэтому независимые анимации могут выполняться в потоке композиции вместо потока пользовательского интерфейса. Это гарантирует, что они остаются плавными, так как нить композиции обновляется с согласованной частотой.
Все эти типы анимаций гарантированно являются независимыми:
Анимация объектов с помощью ключевых кадров
Анимации нулевой длительности
Анимации свойств Canvas.Left и Canvas.Top
Анимации для свойства UIElement.Opacity
Анимации для свойств типа Brush при нацеливании на подсвойство SolidColorBrush.Color
Анимации для следующих свойств UIElement при нацеливании на подпараметры этих типов возвращаемых значений:
Зависимые анимации влияют на макет, который не может быть вычислен без дополнительных данных из потока пользовательского интерфейса. Зависимые анимации включают изменения свойств, таких как ширина и высота . По умолчанию зависимые анимации не выполняются и требуют согласия от разработчика приложения. При включении они выполняются плавно, если поток пользовательского интерфейса остается разблокирован, но они начинают заикаться, если платформа или приложение выполняет много других действий в потоке пользовательского интерфейса.
Почти все анимации в платформе XAML независимы по умолчанию, но есть некоторые действия, которые можно предпринять для отключения этой оптимизации. Особенно остерегайтесь этих сценариев:
- Задание свойства EnableDependentAnimation, чтобы позволить зависимой анимации выполняться в потоке пользовательского интерфейса. Преобразуйте эти анимации в независимую версию. Анимируйте, например, ScaleTransform.ScaleX и ScaleTransform.ScaleY вместо Width и Height объекта. Не бойтесь масштабировать объекты, такие как изображения и текст. Платформа применяет двулинейное масштабирование только в то время как ScaleTransform анимируется. Изображение или текст будут перерастрированы в окончательном размере для обеспечения их постоянной четкости.
- Создание обновлений за кадр, которые фактически зависят от анимаций. Примером этого является применение преобразований в обработчике события CompositonTarget.Rendering.
- Выполнение любой анимации, являющейся независимой, в элементе со свойством CacheMode, равным BitmapCache. Это считается зависимым, так как кэш должен быть повторно растеризован для каждого кадра.
Не анимируйте webView или MediaPlayerElement
Веб-содержимое внутри элемента управления WebView не отображается непосредственно фреймворком XAML и требует дополнительных усилий для интеграции с остальной частью сцены. Эта дополнительная работа добавляется при анимации элемента управления на экране и может привести к проблемам синхронизации (например, HTML-содержимое может не синхронизироваться с остальным содержимым XAML на странице). Если необходимо анимировать элемент управления WebView , замените его на WebViewBrush на весь период анимации.
Анимирование MediaPlayerElement является аналогично плохой идеей. Помимо ущерба производительности, он может вызвать разрывы изображения или другие артефакты в воспроизводимом видеоконтенте.
Примечание Рекомендации в этой статье для MediaPlayerElement также применяются к MediaElement. MediaPlayerElement доступна только в Windows 10 версии 1607, поэтому если вы создаете приложение для предыдущей версии Windows, необходимо использовать MediaElement.
Используйте бесконечные анимации умеренно
Большинство анимаций выполняются в течение определенного периода времени, но при установке свойства Time.Duration Forever анимация может выполняться неограниченное время. Мы рекомендуем свести к минимуму использование бесконечных анимаций, поскольку они постоянно потребляют ресурсы ЦП и могут помешать переходу ЦП в режим пониженного энергопотребления или состояние простоя, что приводит к более быстрому расходу заряда.
Добавление обработчика для CompositionTarget.Rendering аналогично выполнению бесконечной анимации. Обычно поток пользовательского интерфейса активен только при выполнении работы, но добавление обработчика для этого события заставляет его запускать каждый кадр. Удалите обработчик, когда не будет выполнена работа, и повторно зарегистрируйте его, когда это необходимо еще раз.
Использование библиотеки анимации
Пространство имен Windows.UI.Xaml.Media.Animation включает в себя библиотеку высокопроизводительных, гладких анимаций, которые имеют внешний вид и согласованность с другими анимациями Windows. Соответствующие классы имеют "Theme" в названии и описаны в разделе Анимации: обзор. Эта библиотека поддерживает множество распространенных сценариев анимации, таких как анимация первого представления приложения и создание переходов состояния и содержимого. Мы рекомендуем использовать эту библиотеку анимации, если это возможно, чтобы повысить производительность и согласованность пользовательского интерфейса UWP.
Примечание Библиотека анимации не может анимировать все возможные свойства. В XAML-сценариях, когда библиотека анимации не применяется, см. анимации, использующие раскадровку.
Анимировать свойства CompositeTransform3D независимо
Вы можете анимировать каждое свойство CompositeTransform3D независимо, поэтому применяйте только те анимации, которые вам нужны. Примеры и дополнительные сведения см. в разделе UIElement.Transform3D. Дополнительные сведения об анимации преобразований можно найти в разделах анимированные раскадровки и анимации ключевых кадров и анимации с функциями плавности.
Оптимизация ресурсов мультимедиа
Аудио, видео и изображения являются убедительными формами содержимого, которые используют большинство приложений. По мере увеличения частоты захвата мультимедиа и перехода от стандартного определения к высокому определению объем ресурсов, необходимых для хранения, декодировки и воспроизведения этого содержимого увеличивается. Платформа XAML основана на последних функциях, добавленных в подсистемы мультимедиа UWP, чтобы приложения получили эти улучшения бесплатно. Здесь мы описываем некоторые дополнительные приемы, позволяющие максимально эффективно использовать мультимедиа в вашем приложении UWP.
Выпуск потоков мультимедиа
Файлы мультимедиа являются одними из самых распространенных и дорогих ресурсов, которые обычно используют приложения. Поскольку ресурсы мультимедийных файлов могут значительно увеличить объем памяти вашего приложения, необходимо помнить об освобождении дескриптора мультимедиа сразу после того, как приложение завершит работу с ним.
Например, если приложение работает с RandomAccessStream или объектом IInputStream, обязательно вызовите метод закрытия объекта, когда приложение завершит работу с ним, чтобы освободить базовый объект.
Отображение полноэкранного воспроизведения видео по возможности
В приложениях UWP всегда используйте свойство IsFullWindow в MediaPlayerElement для включения и отключения полной отрисовки окон. Это обеспечивает использование оптимизации на уровне системы во время воспроизведения медиаконтента.
Платформа XAML может оптимизировать отображение видеосодержимого, если это единственное, что отрисовывается, что позволяет снизить энергопотребление и повысить частоту кадров. Для наиболее эффективного воспроизведения мультимедиа задайте размер MediaPlayerElement, чтобы он был равен ширине и высоте экрана, без отображения других элементов XAML.
Существуют обоснованные причины наложения элементов XAML на MediaPlayerElement, занимающий полную ширину и высоту экрана, например, закрытые подписи или мгновенные элементы управления воспроизведением. Убедитесь, что скрываете эти элементы (установить Visibility="Collapsed"
), когда они не нужны, чтобы вернуть воспроизведение мультимедиа в наиболее эффективное состояние.
Деактивация дисплея и экономия энергии
Чтобы предотвратить отключение отображения при отсутствии обнаружения действия пользователя, например при воспроизведении видео приложения, можно вызвать DisplayRequest.RequestActive.
Чтобы сохранить питание и время работы батареи, необходимо вызвать DisplayRequest.RequestRelease, чтобы освободить запрос отображения, как только он больше не требуется.
Вот некоторые ситуации, когда следует отменить запрос на отображение:
- Воспроизведение видео приостановлено, например с помощью действия пользователя, буферизации или корректировки из-за ограниченной пропускной способности.
- Воспроизведение останавливается. Например, видео закончилось или презентация закончилась.
- Произошла ошибка воспроизведения. Например, проблемы с сетевым подключением или поврежденный файл.
Поместите другие элементы в сторону встроенного видео
Часто приложения предлагают внедренное представление, в котором воспроизводится видео на странице. Теперь вы, очевидно, потеряли оптимизацию для полного экрана, так как MediaPlayerElement не соответствует размеру страницы, и отображаются другие объекты XAML. Остерегайтесь непреднамеренно вводить этот режим, нарисовав границу вокруг MediaPlayerElement.
Не рисуйте элементы XAML поверх видео, когда оно находится в встроенном режиме. Если вы это сделаете, фреймворк будет вынужден выполнить дополнительную работу, чтобы создать сцену. Размещение элементов управления транспортом под внедренным элементом мультимедиа вместо видео является хорошим примером оптимизации для этой ситуации. На этом изображении красная полоса обозначает набор элементов управления транспортировкой (воспроизведение, приостановка, остановка и т. д.).
Не размещайте эти элементы управления на верхней части носителя, который не является полным экраном. Вместо этого разместите элементы управления воспроизведением за пределами области, в которой отрисовывается мультимедиа. На следующем изображении элементы управления расположены под медиафайлом.
Задержка установки источника для MediaPlayerElement
Подсистемы мультимедиа являются дорогостоящими объектами, а платформа XAML задерживает загрузку библиотек DLL и создает большие объекты до тех пор, пока это возможно. MediaPlayerElement принудительно выполняет эту работу после установки источника через свойство Source. Установка этого параметра, когда пользователь действительно готов воспроизводить медиа, позволяет отложить большую часть затрат, связанных с MediaPlayerElement, насколько это возможно.
Настройка MediaPlayerElement.PosterSource
Параметр MediaPlayerElement.PosterSource позволяет XAML выпускать некоторые ресурсы GPU, которые в противном случае использовались бы. Этот API позволяет приложению использовать как можно меньше памяти.
Улучшение очистки мультимедиа
Очистка контента всегда представляет собой сложную задачу для медиа-платформ, чтобы действительно сделать их реактивными. Как правило, люди делают это путем изменения значения ползунка. Вот несколько советов о том, как сделать это как можно эффективнее:
- Обновите значение элемента ползунка согласно таймеру, который запрашивает положение в MediaPlayerElement.MediaPlayer. Убедитесь, что для таймера используется разумная частота обновления. Свойство Position обновляется только каждые 250 миллисекунда во время воспроизведения.
- Размер частоты шага ползунка должен масштабироваться с длиной видео.
- Подпишитесь на события PointerPressed, PointerMoved, PointerReleased события на ползунке, чтобы задать для свойства PlaybackRate значение 0, когда пользователь перетаскивает пальцем ползунка.
- В обработчике событий PointerReleased вручную установите положение носителя в положение ползунка, чтобы обеспечить оптимальную привязку пальца во время очистки.
Сопоставление разрешения видео с разрешением устройства
Декодирование видео занимает много памяти и циклов GPU, поэтому выберите формат видео близко к разрешению, в котором он будет отображаться. Нет смысла использовать ресурсы для декодирования видео в формате 1080, если оно будет масштабироваться до гораздо меньшего размера. Многие приложения не имеют одного и того же видео, закодированного в разных разрешениях; но если он доступен, используйте кодировку, близкую к разрешению, в котором он будет отображаться.
Выбор рекомендуемых форматов
Выбор формата мультимедиа может быть конфиденциальным и часто определяется бизнес-решениями. С точки зрения производительности UWP мы рекомендуем видео H.264 в качестве основного формата видео и AAC и MP3 в качестве предпочитаемых аудиоформатов. Для воспроизведения локального файла MP4 является предпочтительным контейнером файлов для видеоконтента. Декодирование H.264 ускоряется с помощью последнего графического оборудования. Кроме того, хотя аппаратное ускорение для декодирования VC-1 широко доступно, для большого набора графического оборудования на рынке, ускорение ограничено во многих случаях частичным ускорением (или уровня IDCT), а не полной разгрузкой оборудования на уровне пара (т. е. в режиме VLD).
Если у вас есть полный контроль над процессом создания содержимого видео, необходимо выяснить, как обеспечить хороший баланс между эффективностью сжатия и структурой GOP. Относительно меньший размер GOP с изображениями B может повысить производительность в режимах поиска или специальных режимах.
При включении коротких, низкой задержки звуковых эффектов, например в играх, используйте WAV-файлы с несжатыми данными PCM, чтобы сократить затраты на обработку, типичные для сжатых звуковых форматов.
Оптимизация ресурсов изображений
Масштабирование изображений до соответствующего размера
Изображения записываются с очень высоким разрешением, что может привести к приложениям, использующим больше ЦП при декодировании данных изображения и больше памяти после загрузки с диска. Нет смысла декодировать и сохранять в памяти изображение с высоким разрешением только для того, чтобы показывать его в размере меньше оригинального. Вместо этого создайте версию изображения с точным размером, в котором оно будет отображаться на экране, используя свойства DecodePixelWidth и DecodePixelHeight.
Не делайте этого:
<Image Source="ms-appx:///Assets/highresCar.jpg"
Width="300" Height="200"/> <!-- BAD CODE DO NOT USE.-->
Вместо этого сделайте следующее:
<Image>
<Image.Source>
<BitmapImage UriSource="ms-appx:///Assets/highresCar.jpg"
DecodePixelWidth="300" DecodePixelHeight="200"/>
</Image.Source>
</Image>
Единицы для DecodePixelWidth и DecodePixelHeight по умолчанию являются физическими пикселями. Свойство DecodePixelType можно использовать для изменения этого поведения: установка DecodePixelType в Logical приводит к тому, что размер декодирования автоматически учитывает текущий коэффициент масштабирования системы, аналогично другим элементам XAML. Поэтому обычно целесообразно задать DecodePixelType на Logical, если, например, вы хотите, чтобы DecodePixelWidth и DecodePixelHeight соответствовали свойствам Высота и Ширина элемента управления Image, в котором будет отображаться изображение. При использовании физических пикселей по умолчанию необходимо самостоятельно учитывать текущий коэффициент масштабирования системы; и вы должны прослушивать уведомления об изменении масштаба, если пользователь изменяет свои настройки отображения.
Если значения DecodePixelWidth/Height явно заданы больше, чем изображение будет отображаться на экране, приложение будет ненужно использовать дополнительную память (до 4 байт на пиксель), что быстро становится расточительным для больших изображений. Изображение также будет уменьшено с помощью билинейного масштабирования, что может привести к его размытию при крупных коэффициентах масштабирования.
Если переменные DecodePixelWidth/DecodePixelHeight явно заданы меньше, чем размеры изображения для отображения на экране, то изображение будет увеличено и может показаться пиксельным.
В некоторых случаях, когда соответствующий размер декодирования не может быть определен заранее, следует полагаться на автоматическое декодирование XAML, которое постарается декодировать изображение до нужного размера, если явные параметры DecodePixelWidth/DecodePixelHeight не указаны.
Вы должны задать явный размер декодировки, если вы знаете размер содержимого изображения заранее. Вы также должны совместно установить DecodePixelType в Logical, если указанный размер декодирования соотносится с другими размерами элементов XAML. Например, если вы эксплицитно задали размер содержимого с помощью Image.Width и Image.Height, вы можете установить параметр DecodePixelType на DecodePixelType.Logical, чтобы использовать те же логические размеры пикселей, что и элемент управления Image, а затем эксплицитно использовать BitmapImage.DecodePixelWidth и/или BitmapImage.DecodePixelHeight для управления размером изображения с целью достижения потенциально значительной экономии памяти.
Обратите внимание, что Image.Stretch следует учитывать при определении размера декодированного содержимого.
Оптимальное декодирование
Если вы не задали явный размер декодирования, XAML попытается сохранить память, декодируя изображение до точного размера, которое будет отображаться на экране в соответствии с начальным макетом страницы. Рекомендуется написать приложение таким образом, чтобы использовать эту функцию, когда это возможно. Эта функция будет отключена, если выполнены какие-либо из следующих условий.
- BitmapImage подключен к динамическому дереву XAML после задания содержимого с SetSourceAsync или UriSource.
- Изображение декодируется с помощью синхронного декодирования, например SetSource.
- Изображение скрыто с помощью параметра Opacity со значением 0 или Видимость для Свернутый на исходном изображении элемента, кисти или любого родительского элемента.
- Элемент управления изображения или кисть использует StretchNone.
- Изображение используется как NineGrid .
-
CacheMode="BitmapCache"
устанавливается в элементе image или в любом родительском элементе. - Кисть изображения не прямоугольная (например, при применении к фигуре или тексту).
В приведенных выше сценариях настройка явного размера декодирования — единственный способ добиться экономии памяти.
Перед настройкой источника всегда следует подключить BitmapImage к динамическому дереву. В любой момент, когда элемент изображения или кисть указан в разметке, это будет автоматически происходить. Ниже приведены примеры под заголовком "Примеры динамических деревьев". При настройке источника потока всегда следует избегать использования SetSource и использовать SetSourceAsync. И хорошая идея состоит в том, чтобы избежать скрытия содержимого изображения (либо с нулевой непрозрачностью, либо с свернутой видимостью), ожидая появления события ImageOpened. Это вопрос суждения: вы не сможете воспользоваться автоматической декодировкой оптимального размера, если вы это сделаете. Если приложение должно изначально скрыть содержимое изображения, то при возможности он также должен задать размер декодировки явным образом.
Примеры живых деревьев
Пример 1 (хорошо) — универсальный идентификатор ресурса (URI), указанный в разметке.
<Image x:Name="myImage" UriSource="Assets/cool-image.png"/>
Пример 2 разметки — URI, указанный в коде за кулисами.
<Image x:Name="myImage"/>
Пример 2 кода позади (хорошо) — подключение BitmapImage к дереву перед настройкой UriSource.
var bitmapImage = new BitmapImage();
myImage.Source = bitmapImage;
bitmapImage.UriSource = new URI("ms-appx:///Assets/cool-image.png", UriKind.RelativeOrAbsolute);
Пример 2 (плохо) — установка UriSource объекта BitmapImage перед подключением к дереву.
var bitmapImage = new BitmapImage();
bitmapImage.UriSource = new URI("ms-appx:///Assets/cool-image.png", UriKind.RelativeOrAbsolute);
myImage.Source = bitmapImage;
Оптимизация кэширования
Оптимизация кэширования действует для изображений, использующих UriSource для загрузки содержимого из пакета приложения или из Интернета. Универсальный код ресурса (URI) используется для уникальной идентификации базового содержимого, а платформа XAML не будет загружать или декодировать содержимое несколько раз. Вместо этого он будет использовать кэшированные программные или аппаратные ресурсы для отображения содержимого несколько раз.
Исключение этой оптимизации заключается в том, что изображение отображается несколько раз в разных разрешениях (которые можно задать явным образом или с помощью автоматического декодирования правого размера). Каждая запись кэша также сохраняет разрешение изображения, и если XAML не может найти изображение с исходным универсальным кодом ресурса (URI), соответствующий требуемому разрешению, то он декодирует новую версию с таким размером. Однако он снова не скачивает данные закодированного изображения.
Следовательно, следует использовать UriSource при загрузке образов из пакета приложения и избегать использования потока файлов и SetSourceAsync, если это не требуется.
Изображения в виртуализированных панелях (ListView, например)
Если изображение удаляется из дерева( так как приложение явно удалило его, или потому что оно находится на современной виртуализированной панели и было неявно удалено при прокрутке вне представления), XAML оптимизирует использование памяти путем освобождения аппаратных ресурсов для образа, так как они больше не требуются. Память не освобождается немедленно, но освобождается во время обновления кадра, которое происходит через одну секунду после изъятия элемента изображения из дерева.
Следовательно, необходимо стремиться использовать современные виртуализированные панели для размещения списков изображений.
Программно растеризованные изображения
Если изображение используется для непрямоугольной кисти или для NineGrid, изображение будет использовать программный путь растеризации, который вообще не будет масштабировать изображения. Кроме того, он должен хранить копию образа как в программной, так и в аппаратной памяти. Например, если изображение используется в качестве кисти для эллипса, то потенциально большое полное изображение будет храниться дважды. При использовании NineGrid или непрямоугольной кисти ваше приложение должно предварительно изменять размер изображений до приблизительного размера, в который они будут отображаться.
Загрузка изображений в фоновом потоке
XAML имеет внутреннюю оптимизацию, которая позволяет декодировать содержимое изображения асинхронно на поверхность в аппаратной памяти без необходимости промежуточной поверхности в программной памяти. Это снижает пиковое использование памяти и задержку отрисовки. Эта функция будет отключена, если выполнены какие-либо из следующих условий.
- Изображение используется как NineGrid .
-
CacheMode="BitmapCache"
устанавливается в элементе image или в любом родительском элементе. - Кисть изображения не прямоугольная (например, при применении к фигуре или тексту).
SoftwareBitmapSource
Класс SoftwareBitmapSource осуществляет обмен несжатыми изображениями между различными пространствами имен WinRT, такими как BitmapDecoder, интерфейсы программирования приложений камеры и XAML. Этот класс устраняет необходимость в дополнительной копии, которая обычно требуется с WriteableBitmap, и это помогает уменьшить пиковую память и задержку отображения.
SoftwareBitmap, поставляющий исходную информацию, также можно настроить для использования пользовательского IWICBitmap для обеспечения перезагрузки резервного хранилища, позволяющего приложению переназначать память по мере необходимости. Это расширенный вариант использования C++ .
Приложение должно использовать SoftwareBitmap и SoftwareBitmapSource для взаимодействия с другими API WinRT, которые создают и используют изображения. Приложение должно использовать SoftwareBitmapSource при загрузке несжатых данных изображения вместо WriteableBitmap.
Использование GetThumbnailAsync для эскизов
Одним из вариантов использования масштабирования изображений является создание миниатюр. Хотя вы можете использовать DecodePixelWidth и DecodePixelHeight для предоставления небольших версий изображений, UWP предоставляет еще более эффективные API для получения эскизов. GetThumbnailAsync предоставляет эскизы изображений, которые уже были закэшированы файловой системой. Это обеспечивает еще большую производительность, чем API XAML, так как образ не должен быть открыт или декодирован.
FileOpenPicker picker = new FileOpenPicker();
picker.FileTypeFilter.Add(".bmp");
picker.FileTypeFilter.Add(".jpg");
picker.FileTypeFilter.Add(".jpeg");
picker.FileTypeFilter.Add(".png");
picker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
StorageFile file = await picker.PickSingleFileAsync();
StorageItemThumbnail fileThumbnail = await file.GetThumbnailAsync(ThumbnailMode.SingleItem, 64);
BitmapImage bmp = new BitmapImage();
bmp.SetSource(fileThumbnail);
Image img = new Image();
img.Source = bmp;
Dim picker As New FileOpenPicker()
picker.FileTypeFilter.Add(".bmp")
picker.FileTypeFilter.Add(".jpg")
picker.FileTypeFilter.Add(".jpeg")
picker.FileTypeFilter.Add(".png")
picker.SuggestedStartLocation = PickerLocationId.PicturesLibrary
Dim file As StorageFile = Await picker.PickSingleFileAsync()
Dim fileThumbnail As StorageItemThumbnail = Await file.GetThumbnailAsync(ThumbnailMode.SingleItem, 64)
Dim bmp As New BitmapImage()
bmp.SetSource(fileThumbnail)
Dim img As New Image()
img.Source = bmp
Декодирование изображений один раз
Чтобы предотвратить декодирование изображений более одного раза, назначьте свойство Image.Source из URI вместо использования потоков памяти. Платформа XAML может связать один и тот же URI в нескольких местах с одним декодированным изображением, но не может сделать то же самое для нескольких потоков памяти, содержащих одни и те же данные, и создает другое декодированное изображение для каждого потока памяти.