Задержка перехода фрагмента, вызванная медленным измерением / проходом макета - PullRequest
0 голосов
/ 12 мая 2018

Мое приложение содержит список элементов, и при нажатии на них появляется фрагмент с подробной информацией об элементе.Детали содержат довольно сложный RecyclerView (много маленьких представлений с FlexBoxLayoutManager), и проход измерения / макета может превышать 50 мс.

Эта задержка приводит к тому, что приложение отбрасывает несколько кадров в начале перехода фрагментавызывая довольно заметный «прыжок».

Я вижу несколько возможных способов избежать этого:

  1. Не заполняйте RecyclerView (или сделайте его заглушкой) до переходазакончен.Недостаток: пользователь видит анимированный полупустой фрагмент.
  2. Задержка всего перехода до тех пор, пока новый фрагмент не будет измерен и выложен.Недостаток: обратная связь с пользователем задерживается.
  3. Запустите анимацию выхода из списка, но задержите анимацию ввода, пока новый фрагмент не будет измерен и выложен.Это то, что я хотел бы сделать.

К сожалению, анимация выхода должна была бы выполняться в основном потоке, и то же самое касается меры / макета;нет ничего похожего на AsyncLayoutInflater для меры / макета, верно?

Итак, разве нет способа реализовать # 3?Если это так, у кого-нибудь есть лучшее решение?

Демонстрационное приложение

Это приложение просто добавляет режим сна в метод onMeasure() всякий раз, когда установлен флажок "медленная мера".

Вот экранная запись - обратите внимание на разницу при переключении флажка, как он прыгает (наиболее заметно слева с текстом и по правому краю между старым / новым фрагментом).

MainActivity.kt

var beSlow = false

class SlowWidget @JvmOverloads constructor(
        context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : TextView(context, attrs, defStyleAttr) {
    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        if (beSlow) {
            SystemClock.sleep(100)
        }
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
    }
}

class SlowFragment : Fragment() {
    override fun onCreateView(inflater: LayoutInflater, parent: ViewGroup?, state: Bundle?): View {
        return inflater.inflate(R.layout.fragment, parent, false)
    }
}

class MainActivity : AppCompatActivity() {
    var i = 0
    val colors = arrayOf(Color.RED, Color.GREEN, Color.BLUE, Color.YELLOW, Color.CYAN)

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.main)
    }

    fun viewClicked(v: View): Unit {
        beSlow = slowbox.isChecked
        supportFragmentManager.beginTransaction()
                .setCustomAnimations(R.anim.slide_in, R.anim.slide_out)
                .replace(R.id.container, SlowFragment().apply {
                    arguments = Bundle().apply {
                        putInt("color", colors[i++ % colors.size])
                    }
                })
                .commit()
    }
}

res / layout / main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <Button
        android:text="Switch"
        android:onClick="viewClicked"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
    <CheckBox
        android:id="@+id/slowbox"
        android:text="slow measure"
        android:checked="true"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</LinearLayout>

res / layout / фрагмент.xml

<?xml version="1.0" encoding="utf-8"?>
<se.dolkow.debug.animdemo.SlowWidget
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:text="Hello World!"
    android:textColor="#000"
    android:gravity="center_vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/rainbow"
    />

res / drawable / rainbow.xml

<?xml version="1.0" encoding="utf-8"?>
<shape
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle"
    >
    <gradient
        android:startColor="#ffff0000"
        android:centerColor="#ff00ff00"
        android:endColor="#ff8000ff"
        />
</shape>

res / anim / slide_in.xml

<?xml version="1.0" encoding="utf-8"?>
<set
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="1000"
    android:shareInterpolator="false"
    >
    <translate android:fromXDelta="100%p" android:toXDelta="0"
        android:interpolator="@android:anim/linear_interpolator" />
</set>

res / anim / slide_out.xml

<?xml version="1.0" encoding="utf-8"?>
<set
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="1000"
    android:shareInterpolator="false">
    <translate android:fromXDelta="0" android:toXDelta="-100%p"
        android:interpolator="@android:anim/linear_interpolator" />
</set>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...