Мое приложение содержит список элементов, и при нажатии на них появляется фрагмент с подробной информацией об элементе.Детали содержат довольно сложный RecyclerView (много маленьких представлений с FlexBoxLayoutManager), и проход измерения / макета может превышать 50 мс.
Эта задержка приводит к тому, что приложение отбрасывает несколько кадров в начале перехода фрагментавызывая довольно заметный «прыжок».
Я вижу несколько возможных способов избежать этого:
- Не заполняйте RecyclerView (или сделайте его заглушкой) до переходазакончен.Недостаток: пользователь видит анимированный полупустой фрагмент.
- Задержка всего перехода до тех пор, пока новый фрагмент не будет измерен и выложен.Недостаток: обратная связь с пользователем задерживается.
- Запустите анимацию выхода из списка, но задержите анимацию ввода, пока новый фрагмент не будет измерен и выложен.Это то, что я хотел бы сделать.
К сожалению, анимация выхода должна была бы выполняться в основном потоке, и то же самое касается меры / макета;нет ничего похожего на 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>