Intereting Posts
Как программно заставить обнаружение услуг с низким энергопотреблением Bluetooth на Android без использования кеша Android Studio: Зависимости моментальных снимков не обновляются должным образом Отображать состояние прямо из холодного старта Ускоренные звонки и андроид Как скачать файл с сервисом в Android? Сюрпризное поведение eclipse для файлов C при использовании JNI. Почему? Error: не удается найти метод символов getMap () после обновления зависимостей Отображение изображения YUV в Android ViewPager с фрагментами внутри PopupWindow (или DialogFragment) – ошибка не найдена для id для фрагмента Gradle, Robolectric и Espresso FirebaseAuth.getCurrentUser () return null DisplayName Android: как передать объект Parcelable в цель и использовать getParcelable метод bundle? Просмотр подкачки Установка старого Android SDK с использованием Homebrew Обнаруживать программно, если устройство Android может выполнять шифрование данных

Анимация фрагмента 3-х панелей заикается

Информация о внедрении: я внедрил 3-х панельный макет после ответа CommonsWare, размещенного по его собственному вопросу: Полный рабочий пример сценария анимации с тремя фрагментами Gmail?

Как общая идея, у меня есть макет, состоящий из следующих уровней (от 1 до 3):

  1. MainActivity
  2. SlidingMenu (Side UI pattern) фрагмент скрывается с левой стороны и ContentFragment как фрагмент, в котором размещается макет 3-х панелей.
  3. Внутри ContentFragment : LeftListFragment (строки с 3 MiddleListFragment ), MiddleListFragment (строки с 8 DetailFragment каждый), DetailFragment .

LeftListFragment и MiddleListFragment используют CursorLoaders для загрузки данных из ContentProvider внутри каждого списка. DetailFragment также вызывает курсор с данными при необходимости. Поэтому я даже не реализовал пользовательские Adapters (гораздо более приятный дизайн). Затем я добавил 3 панели макета + анимации. Что касается работы, он работает по назначению, никаких проблем нет. Время Animation – 500 мс.

Проблема: анимации заикаются немного. Несколько отброшенных кадров. И когда видны Left и Middle, и я нажимаю на элемент Middle list, чтобы открыть Detail; А также когда я нажимаю кнопку «Назад», чтобы снова увидеть списки слева и внизу (когда ничего не загружается).

То, что я пробовал:

  1. Удален код, который загружает фрагмент в DetailView . Я просто MiddleFragment элемент в MiddleFragment и начинается анимация, без какой-либо детализации, фактически загружаемой. Все еще заикается. Кроме того, при ударе назад ничего не загружается, и он все еще заикается, поэтому я полагаю, что загрузчики / курсоры не являются причиной этого.
  2. Я использовал dumpsys gfxinfo, чтобы увидеть среднее время в мс для вычисления каждого кадра. Действительно, время avg для вычисления составляет 18 мс, что выше порога 16 мс. Значит ли это, что заикание происходит из-за времени, которое требуется, чтобы снова рисовать списки при анимации? Если да, то почему? Я имею в виду … У меня нет изображений вообще внутри строк. И я не мог испортить код Adapters, потому что я не написал ничего …
  3. Сокращение времени Animation от 500 мс до 200 мс. Он все еще заикается, если вы смотрите внимательно, это просто быстрее.

EDIT: я переключился с rightPaneWidth на leftPaneWidth ниже (да, это удаляет анимацию leftPaneWidth ), и заикание теперь исчезло. Список по-прежнему скользит влево, но он просто не становится меньше по ширине. Итак, если больше не заикается, значит ли это, что проблема с ObjectAnimator в моем коде?

 ObjectAnimator.ofInt(this, "middleWidth", rightPaneWidth, leftPaneWidth) .setDuration(ANIM_DURATION).start(); 

Спасибо за ваше время !

Код для 3-х панельных макетов:

 package com.xyz.view.widget; import android.animation.ObjectAnimator; import android.annotation.SuppressLint; import android.annotation.TargetApi; import android.content.Context; import android.util.AttributeSet; import android.view.View; import android.view.ViewPropertyAnimator; import android.widget.LinearLayout; public class ThreePaneLayout extends LinearLayout { private View leftView = null; private View middleView = null; private View rightView = null; private static final int ANIM_DURATION = 500; private int leftPaneWidth = -1; private int rightPaneWidth = -1; // ------------------------------------------------------------------------------------------- // -------------- Constructor // ------------------------------------------------------------------------------------------- public ThreePaneLayout(Context context, AttributeSet attrs) { super(context, attrs); setOrientation(HORIZONTAL); } @Override public void onFinishInflate() { super.onFinishInflate(); leftView = getChildAt(0); middleView = getChildAt(1); rightView = getChildAt(2); } // ------------------------------------------------------------------------------------------- // -------------- Public methods // ------------------------------------------------------------------------------------------- public View getLeftView() { return leftView; } public View getMiddleView() { return middleView; } public View getRightView() { return rightView; } @SuppressLint("NewApi") public void hideLeft() { if (leftPaneWidth == -1) { leftPaneWidth = leftView.getWidth(); rightPaneWidth = middleView.getWidth(); resetWidget(leftView, leftPaneWidth); resetWidget(middleView, rightPaneWidth); resetWidget(rightView, rightPaneWidth); requestLayout(); } translateWidgets(-1 * leftPaneWidth, leftView, middleView, rightView); ObjectAnimator.ofInt(this, "middleWidth", rightPaneWidth, leftPaneWidth) .setDuration(ANIM_DURATION).start(); } @SuppressLint("NewApi") public void showLeft() { translateWidgets(leftPaneWidth, leftView, middleView, rightView); ObjectAnimator.ofInt(this, "middleWidth", leftPaneWidth, rightPaneWidth) .setDuration(ANIM_DURATION) .start(); } // ------------------------------------------------------------------------------------------- // -------------- Private methods // ------------------------------------------------------------------------------------------- private void setMiddleWidth(int value) { middleView.getLayoutParams().width = value; requestLayout(); } @TargetApi(12) private void translateWidgets(int deltaX, View... views) { for (final View view : views) { ViewPropertyAnimator viewPropertyAnimator = view.animate(); viewPropertyAnimator.translationXBy(deltaX) .setDuration(ANIM_DURATION); } } private void resetWidget(View view, int width) { LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams)view.getLayoutParams(); layoutParams.width = width; layoutParams.weight = 0; } } по package com.xyz.view.widget; import android.animation.ObjectAnimator; import android.annotation.SuppressLint; import android.annotation.TargetApi; import android.content.Context; import android.util.AttributeSet; import android.view.View; import android.view.ViewPropertyAnimator; import android.widget.LinearLayout; public class ThreePaneLayout extends LinearLayout { private View leftView = null; private View middleView = null; private View rightView = null; private static final int ANIM_DURATION = 500; private int leftPaneWidth = -1; private int rightPaneWidth = -1; // ------------------------------------------------------------------------------------------- // -------------- Constructor // ------------------------------------------------------------------------------------------- public ThreePaneLayout(Context context, AttributeSet attrs) { super(context, attrs); setOrientation(HORIZONTAL); } @Override public void onFinishInflate() { super.onFinishInflate(); leftView = getChildAt(0); middleView = getChildAt(1); rightView = getChildAt(2); } // ------------------------------------------------------------------------------------------- // -------------- Public methods // ------------------------------------------------------------------------------------------- public View getLeftView() { return leftView; } public View getMiddleView() { return middleView; } public View getRightView() { return rightView; } @SuppressLint("NewApi") public void hideLeft() { if (leftPaneWidth == -1) { leftPaneWidth = leftView.getWidth(); rightPaneWidth = middleView.getWidth(); resetWidget(leftView, leftPaneWidth); resetWidget(middleView, rightPaneWidth); resetWidget(rightView, rightPaneWidth); requestLayout(); } translateWidgets(-1 * leftPaneWidth, leftView, middleView, rightView); ObjectAnimator.ofInt(this, "middleWidth", rightPaneWidth, leftPaneWidth) .setDuration(ANIM_DURATION).start(); } @SuppressLint("NewApi") public void showLeft() { translateWidgets(leftPaneWidth, leftView, middleView, rightView); ObjectAnimator.ofInt(this, "middleWidth", leftPaneWidth, rightPaneWidth) .setDuration(ANIM_DURATION) .start(); } // ------------------------------------------------------------------------------------------- // -------------- Private methods // ------------------------------------------------------------------------------------------- private void setMiddleWidth(int value) { middleView.getLayoutParams().width = value; requestLayout(); } @TargetApi(12) private void translateWidgets(int deltaX, View... views) { for (final View view : views) { ViewPropertyAnimator viewPropertyAnimator = view.animate(); viewPropertyAnimator.translationXBy(deltaX) .setDuration(ANIM_DURATION); } } private void resetWidget(View view, int width) { LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams)view.getLayoutParams(); layoutParams.width = width; layoutParams.weight = 0; } } 

XML для ContentFragment:

  <?xml version="1.0" encoding="utf-8"?> <com.xyz.view.widget.ThreePaneLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/fragment_content_three_pane_layout" android:layout_width="match_parent" android:layout_height="match_parent" > <FrameLayout android:id="@+id/fragment_content_framelayout_left" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="3" /> <FrameLayout android:id="@+id/fragment_content_framelayout_middle" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="7" /> <FrameLayout android:id="@+id/fragment_content_framelayout_right" android:layout_width="0dp" android:layout_height="match_parent" /> </com.xyz.view.widget.ThreePaneLayout> 

Проблема не в ObjectAnimator, а в том, что ваше приложение просто делает слишком много для каждого кадра анимации. В частности, вы анимируете параметры макета и запрашиваете макет на каждом кадре. Макет является мощным и полезным … но может быть довольно дорогостоящим в любой, но самой тривиальной иерархии представлений. Важно избегать дорогостоящих операций за кадр во время анимации, а макет попадает в эту «дорогую» категорию. Раздвижные вещи прекрасны (переводX / Y), затухание вещей в / из хорошо (альфа), но на самом деле прокладывает все на каждом кадре? Просто сказать нет.

Я закончил полностью удаление ObjectAnimator … Конечно, у него все еще есть анимация слайдов, но в то же время не выполняется плавное изменение размера. Не то, чтобы это было действительно гладкое …

В любом случае, если кто-то действительно придумает реальное решение этой проблемы, не стесняйтесь делиться. Благодарю.

 package com.anfuddle.view.widget; import android.annotation.TargetApi; import android.content.Context; import android.os.Build; import android.util.AttributeSet; import android.view.View; import android.view.ViewPropertyAnimator; import android.widget.LinearLayout; public class ThreePaneLayout extends LinearLayout { private View leftView = null; private View middleView = null; private View rightView = null; private static final int ANIM_DURATION = 500; private int rootWidth = -1; private int leftPaneWidth = -1; private int rightPaneWidth = -1; // ------------------------------------------------------------------------------------------- // -------------- Constructor // ------------------------------------------------------------------------------------------- public ThreePaneLayout(Context context, AttributeSet attrs) { super(context, attrs); setOrientation(HORIZONTAL); } @Override public void onFinishInflate() { super.onFinishInflate(); leftView = getChildAt(0); middleView = getChildAt(1); rightView = getChildAt(2); } // ------------------------------------------------------------------------------------------- // -------------- Public methods // ------------------------------------------------------------------------------------------- public View getLeftView() { return leftView; } public View getMiddleView() { return middleView; } public View getRightView() { return rightView; } @TargetApi(Build.VERSION_CODES.HONEYCOMB) public void hideLeftAndMiddle() { if (leftPaneWidth == -1) { rootWidth = getWidth(); leftPaneWidth = leftView.getWidth(); rightPaneWidth = middleView.getWidth(); } resetWidget(leftView, leftPaneWidth); resetWidget(middleView, rightPaneWidth); resetWidget(rightView, rootWidth); requestLayout(); translateWidgets(-1 * rootWidth, leftView, middleView, rightView); } @TargetApi(Build.VERSION_CODES.HONEYCOMB) public void hideLeft() { if (leftPaneWidth == -1) { leftPaneWidth = leftView.getWidth(); rightPaneWidth = middleView.getWidth(); } resetWidget(leftView, leftPaneWidth); resetWidget(middleView, leftPaneWidth); resetWidget(rightView, rightPaneWidth); requestLayout(); translateWidgets(-1 * leftPaneWidth, leftView, middleView, rightView); } @TargetApi(Build.VERSION_CODES.HONEYCOMB) public void showLeftAndMiddle() { translateWidgets(rootWidth, leftView, middleView, rightView); } @TargetApi(Build.VERSION_CODES.HONEYCOMB) public void showLeft() { resetWidget(leftView, leftPaneWidth); resetWidget(middleView, rightPaneWidth); resetWidget(rightView, rightPaneWidth); requestLayout(); translateWidgets(leftPaneWidth, leftView, middleView, rightView); } // ------------------------------------------------------------------------------------------- // -------------- Private methods // ------------------------------------------------------------------------------------------- @TargetApi(12) private void translateWidgets(int deltaX, View... views) { for (final View view : views) { ViewPropertyAnimator viewPropertyAnimator = view.animate(); viewPropertyAnimator.translationXBy(deltaX) .setDuration(ANIM_DURATION); } } private void resetWidget(View view, int width) { LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams)view.getLayoutParams(); layoutParams.width = width; layoutParams.weight = 0; } } по package com.anfuddle.view.widget; import android.annotation.TargetApi; import android.content.Context; import android.os.Build; import android.util.AttributeSet; import android.view.View; import android.view.ViewPropertyAnimator; import android.widget.LinearLayout; public class ThreePaneLayout extends LinearLayout { private View leftView = null; private View middleView = null; private View rightView = null; private static final int ANIM_DURATION = 500; private int rootWidth = -1; private int leftPaneWidth = -1; private int rightPaneWidth = -1; // ------------------------------------------------------------------------------------------- // -------------- Constructor // ------------------------------------------------------------------------------------------- public ThreePaneLayout(Context context, AttributeSet attrs) { super(context, attrs); setOrientation(HORIZONTAL); } @Override public void onFinishInflate() { super.onFinishInflate(); leftView = getChildAt(0); middleView = getChildAt(1); rightView = getChildAt(2); } // ------------------------------------------------------------------------------------------- // -------------- Public methods // ------------------------------------------------------------------------------------------- public View getLeftView() { return leftView; } public View getMiddleView() { return middleView; } public View getRightView() { return rightView; } @TargetApi(Build.VERSION_CODES.HONEYCOMB) public void hideLeftAndMiddle() { if (leftPaneWidth == -1) { rootWidth = getWidth(); leftPaneWidth = leftView.getWidth(); rightPaneWidth = middleView.getWidth(); } resetWidget(leftView, leftPaneWidth); resetWidget(middleView, rightPaneWidth); resetWidget(rightView, rootWidth); requestLayout(); translateWidgets(-1 * rootWidth, leftView, middleView, rightView); } @TargetApi(Build.VERSION_CODES.HONEYCOMB) public void hideLeft() { if (leftPaneWidth == -1) { leftPaneWidth = leftView.getWidth(); rightPaneWidth = middleView.getWidth(); } resetWidget(leftView, leftPaneWidth); resetWidget(middleView, leftPaneWidth); resetWidget(rightView, rightPaneWidth); requestLayout(); translateWidgets(-1 * leftPaneWidth, leftView, middleView, rightView); } @TargetApi(Build.VERSION_CODES.HONEYCOMB) public void showLeftAndMiddle() { translateWidgets(rootWidth, leftView, middleView, rightView); } @TargetApi(Build.VERSION_CODES.HONEYCOMB) public void showLeft() { resetWidget(leftView, leftPaneWidth); resetWidget(middleView, rightPaneWidth); resetWidget(rightView, rightPaneWidth); requestLayout(); translateWidgets(leftPaneWidth, leftView, middleView, rightView); } // ------------------------------------------------------------------------------------------- // -------------- Private methods // ------------------------------------------------------------------------------------------- @TargetApi(12) private void translateWidgets(int deltaX, View... views) { for (final View view : views) { ViewPropertyAnimator viewPropertyAnimator = view.animate(); viewPropertyAnimator.translationXBy(deltaX) .setDuration(ANIM_DURATION); } } private void resetWidget(View view, int width) { LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams)view.getLayoutParams(); layoutParams.width = width; layoutParams.weight = 0; } }