Информация о реализации: Я реализовал 3-х панельный макет после ответа CommonsWare, размещенного по его собственному вопросу: Полный рабочий пример сценария анимации с тремя фрагментами Gmail
Как общая идея, у меня есть макет, состоящий из следующих уровней (от 1 до 3):
-
MainActivity
-
SlidingMenu
(паттерн пользовательского интерфейса боковой панели), скрывающийся с левой стороны, иContentFragment
в качестве фрагмента, в котором размещается макет 3-х панелей. - Внутри
ContentFragment
:LeftListFragment
(строки с 3 текстовыми полями),MiddleListFragment
(строки с 8 текстовыми полями каждый),DetailFragment
.
LeftListFragment
и MiddleListFragment
используйте CursorLoaders
для загрузки данных из ContentProvider
внутри каждого списка. DetailFragment
также вызывает курсор с данными при необходимости. Поэтому я даже не реализовал пользовательский Adapters
(гораздо более приятный дизайн). Затем я добавил 3 панели макета + анимации. Что касается работы, он работает по назначению, никаких проблем нет. Animation
время составляет 500 мс.
Проблема: Анимации немного заикаются. Несколько отброшенных кадров. И когда видны Left и Middle, и я нажимаю на элемент Middle list, чтобы открыть Detail; а также когда я нажимаю кнопку "Назад", чтобы снова увидеть списки "Левый" и "Средний" (когда ничего не загружается).
Что я пробовал:
- Удален код, загружающий фрагмент в
DetailView
. Я просто нажимаю элемент вMiddleFragment
и начинается анимация, без какой-либо детализации, фактически загружаемой. Все еще заикается. Кроме того, при ударе назад ничего не загружается, и он все еще заикается, поэтому я полагаю, что загрузчики/курсоры не являются причиной этого. - Я использовал dumpsys gfxinfo, чтобы увидеть среднее время в мс для вычисления каждого кадра. Действительно, среднее время для вычисления составляет 18 мс, что выше порога 16 мс. Значит ли это, что заикание происходит из-за времени, необходимого для повторного рисования списков при анимации? Если да, то почему? Я имею в виду... У меня нет изображений вообще внутри строк. И я не мог испортить код Adapters, потому что я не написал ничего...
- Сокращение времени
Animation
от 500 мс до 200 мс. Он все еще заикается, если вы смотрите внимательно, это происходит быстрее.
EDIT: Я переключился с rightPaneWidth
на 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;
}
}
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>