Intereting Posts

Как определить анимацию размера экрана в формате XML

Я создал Animation для Fragments в своем приложении. Animation анимирует перемещение между вкладками, для этого мне нужно оживить текущий Fragment чтобы полностью переместиться с экрана, в то время как Fragment сместился с противоположной стороны. Вид как Animation ViewPager использует ViewPager .

Мне нужно указать абсолютную начальную и конечную позицию представления, и поскольку разные устройства имеют разные размеры, я не могу определить Animation в XML, которая подходит для всех устройств. На более крупном устройстве View может полностью не скользить по экрану, а на более маленьком устройстве View перемещается на много и продолжает двигаться, когда он уже выключен.

Поэтому я предполагаю, что мой вопрос: как я могу определить анимацию в XML, которая выведет Fragment с экрана и в то же время поместится на всех устройствах?

Моя анимация:

 <?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android"> <objectAnimator xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@android:anim/linear_interpolator" android:propertyName="x" android:valueType="floatType" android:valueTo="720" android:valueFrom="0" android:duration="300"/> </set> 

Solutions Collecting From Web of "Как определить анимацию размера экрана в формате XML"

1) Что касается щедрости:

Существующие ответы на SO предлагают подклассу FrameLayout …

Если вы хотите использовать ObjectAnimator вас нет выбора, кроме как подклассировать View который хотите оживить. Вам необходимо предоставить ObjectAnimator необходимые методы getter и setter, чтобы сделать свою магию, поскольку она по сути просто вызывает эти методы getter и setter для выполнения Animation .

Вопрос, который вы связываете с ( Анимация перехода между фрагментами ), представляет собой подклассу FrameLayout для добавления setXFraction() и getXFraction() . Они реализованы таким образом, чтобы установить значение x относительно ширины FrameLayout . Только делая это, ObjectAnimator может сделать что-нибудь еще, кроме анимирования между абсолютными значениями.

Итак, чтобы обобщить, ObjectAnimator сам по себе не делает много анимации, он просто вызывает методы getter и setter посредством отражения.

Не существует способа получить фактические размеры пикселов экрана (а не только dp) в xml-файле?

С ObjectAnimator нет способа добиться этого. ObjectAnimators просто интерполируются от значения начала и конца. Как я объяснил выше, метод setter определяет, что на самом деле происходит.

Например, вызов пользовательской функции, которая возвращает ширину, будет прекрасной или определит константу, которую может установить код, имея код, заданный константой равным ширине экрана, тогда доступ к этой константе из xml был бы одинаково полезен.

Вы не можете вставлять какое-либо значение из кода в любой ресурс xml. Все, что содержится в ваших xml-файлах, скомпилировано в ваш APK при его создании и не может быть изменено во время выполнения. И это также ответ на ваш другой вопрос: нет ресурса или константы или чего-либо, что было бы доступно в xml, который содержит текущий размер экрана. Динамические значения, такие как размер экрана устройства, на котором установлено приложение, не могут быть частью этих ресурсов, поскольку все в них скомпилировано в ваше приложение при его создании.


2) Возможное решение: просмотр анимаций

Одним из возможных решений является использование анимаций представлений вместо ObjectAnimator . С анимацией просмотра вы можете указать фракции вместо абсолютных значений:

 <set xmlns:android="http://schemas.android.com/apk/res/android"> <translate android:fromYDelta="-100%" android:toYDelta="0%" android:duration="1000"/> </set> 

Это позволит оживить View с -100% до 0% высоты экрана. Иными словами, от полного экрана до положения View . Вы можете использовать его следующим образом:

 Animation animation = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.slide_down); view.startAnimation(animation); 

Я понимаю, что это может не помочь вам. Есть случаи, когда нужно использовать ObjectAnimators и не использовать анимацию просмотра. Но пока вы можете использовать анимацию вида, это должно в значительной степени решить вашу проблему.

  • Ссылка на документацию
  • Связанный вопрос

3) Лучшая практика

То, что мы действительно должны рассматривать здесь, – это то, что я считаю ошибочным с вашей стороны. Как вы уже заметили, каждая анимация, которую вы определяете в xml, имеет абсолютные начальные и конечные значения. Эти значения являются статическими и не могут быть изменены после компиляции вашего приложения.

Если вы посмотрите, как работают ресурсы с множеством доступных селекторов, а также с dp, sp … тогда вы поймете, что он предназначен для того, чтобы сделать одно:
Вы можете, например, определить анимацию, которая перемещает View на 100dp. Dp – это измерение физического размера, 100dp будет точно таким же физическим размером на любом экране с любой плотностью пикселей. С помощью селекторов вы можете изменить эту анимацию для устройств с меньшими или большими экранами, где анимация может перемещать View слишком много или слишком мало. Но вы можете заполнить только статические значения. Помимо работы с селекторами, вы не можете настроить анимацию для каждого устройства.

Итак, вы видите, что ресурсы действительно предназначены для всего, что является статичным и неизменным. Он отлично подходит для измерений или строковых переводов, но иногда с анимацией может быть немного боли. Как я сказал выше, только анимация просмотра обеспечивает путь вокруг статического характера, предоставляя опцию определения фракций вместо абсолютных значений. Но в целом вы не можете определить что-либо динамическое в xml.

Чтобы подтвердить этот аргумент, посмотрите на отличные видеоролики DevBytes Google об анимации:

  • Просмотр анимаций
  • Анимация пользовательской активности
  • Анимация с картой
  • Анимация недвижимости
  • Анимация ListView

Тогда вы заметите, что ни одна анимация в этих примерах никогда не определена в xml. Конечно, можно утверждать, что они не определяют их в xml, потому что они хотят легче объяснить и показать код, но, на мой взгляд, это еще раз доказывает одно:

Вы не можете определить анимацию в статических ресурсах, которая зависит от чисто динамического значения

Так как ширина / высота экрана будет отличаться от устройства к устройству, вам нужны разные анимации для каждого устройства. Только анимация просмотра обеспечивает такой подход, поскольку они позволяют вам определять фракции вместо абсолютных значений. В любом другом случае вам понадобится программно определить анимацию. К счастью, это не сложно с ObjectAnimators :

 Animator animator = ObjectAnimator.ofFloat(view, View.X, startValue, endValue); animator.start(); 

Это позволит анимировать положение x в View от начала до конечного значения в пикселях. Вы можете передать ширину представления, чтобы оживить ее так, как вы хотите:

 Animator animator = ObjectAnimator.ofFloat(view, View.X, -view.getWidth(), 0.0f); animator.start(); 

Это позволит анимировать View чтобы он скользил слева. Он полностью начинается с экрана и останавливается в конечном положении. Вы также можете просто сделать это:

 view.animate().x(targetValue); 

Это позволит оживить View от его текущей позиции x до целевого значения x.

Но, пожалуйста, не поймите меня неправильно, вы все равно должны пытаться определить как можно больше – будь то анимация или что-то еще – в ресурсах. Анимация жесткого кодирования или любое другое значение следует избегать как можно больше, если это не необходимо, как в вашем случае.


4) Резюме

Итак, чтобы подвести итог:

  • Вы не можете делать то, что хотите делать с ObjectAnimators не добавляя методы getter и setter, необходимые для View вы хотите оживить.
  • Если возможно, используйте анимацию просмотра . С их помощью вы можете определить анимацию, основанную на долях ширины или высоты представления.
  • Если вышеизложенное не работает или не применимо к вашей ситуации, тогда программным образом определите анимацию, это будет работать в любом случае.

Надеюсь, я смогу вам помочь, и если у вас возникнут какие-либо вопросы, не стесняйтесь спрашивать!

Просто создайте разные папки на основе плотности экрана.

Так что скажем, ваш xml для анимации находится в папке с именем anim (в родительской папке res).

Затем создайте анимацию-ldpi, anim-mdpi и т. Д. В res. Поместите свою соответствующую анимацию в каждую из этих папок, которые представляют плотность экрана, и андроид выберет правильный.

Кто-то просил мое рабочее решение. Вот. Это код C # через Mono. Надеюсь, авторы Java могут понять, что должно быть на этом языке.

 public class MyFragment: Fragment { public int TransitDuration { get { return 500; } } public override Animator OnCreateAnimator(FragmentTransit transit, bool enter, int nextAnim) { switch (transit) { case FragmentTransit.FragmentOpen: { if (enter) { return this.EnterFromLeftAnimator; } else { return this.ExitToRightAnimator; } } case FragmentTransit.FragmentClose: { if (enter) { return this.EnterFromRightAnimator; } else { return this.ExitToLeftAnimator; } } default: Animator r = base.OnCreateAnimator(transit, enter, nextAnim); if (r == null) { if (!this.IsAdded) { this.OnContextHidden(); } } return r; } } public Animator EnterFromLeftAnimator { get { float width = Screen.MainScreen.PixelSize.Width; // this is an object of mine; other code cached the width there long ago. It would actually be better to use the window width. ObjectAnimator animator = ObjectAnimator.OfFloat(this, "X", width, 0); animator.SetDuration(this.TransitDuration); Animator r = animator as Animator; return r; } } public Animator ExitToRightAnimator { get { float width = Screen.MainScreen.PixelSize.Width; ObjectAnimator animator = ObjectAnimator.OfFloat(this, "X", 0, -width); animator.SetDuration(this.TransitDuration); Animator r = animator as Animator; r.AddListener(new AnimatorEndListenerAdapter(() => this.OnContextHidden())); return r; } } public Animator EnterFromRightAnimator { get { float width = this.ScreenWidth; ObjectAnimator animator = ObjectAnimator.OfFloat(this, "X", -width, 0); animator.SetDuration(this.TransitDuration); Animator r = animator as Animator; return r; } } public Animator ExitToLeftAnimator { get { float width = this.ScreenWidth; ObjectAnimator animator = ObjectAnimator.OfFloat(this, "X", 0, width); animator.SetDuration(this.TransitDuration); Animator r = animator as Animator; r.AddListener(new AnimatorEndListenerAdapter(() => this.OnContextHidden())); return r; } } public override void OnActivityCreated(Bundle savedInstanceState) { base.OnActivityCreated(savedInstanceState); this.RetainInstance = true; } }