2021年3月5日金曜日

ViewPager2 で 遠くのページに smoothScroll するときは 3ページ前から作られる

最初 index : 0

タブクリックで index : 15 のページに移動

タブクリックで index : 4 のページに移動


したときの Fragment のライフサイクルの結果は次のようになります。 : onCreate : 0 : onCreate : 12 : onCreate : 13 : onCreate : 14 : onCreate : 15 : onDestroy : 0 : onDestroy : 12 : onCreate : 7 : onDestroy : 13 : onCreate : 6 : onCreate : 5 : onDestroy : 14 : onCreate : 4 : onDestroy : 15 : onDestroy : 7 index : 0 から index : 15 のページに移動するとき、index : 12 のページから作られていることがわかります。
同じように index : 15 から index : 4 のページに移動するときは index : 7 のページから作られていることがわかります。


この 3 ページ前からというロジックは ViewPager2 の setCurrentItemInternal() に実装されています。 void setCurrentItemInternal(int item, boolean smoothScroll) { ... // For smooth scroll, pre-jump to nearby item for long jumps. if (Math.abs(item - previousItem) > 3) { mRecyclerView.scrollToPosition(item > previousItem ? item - 3 : item + 3); // TODO(b/114361680): call smoothScrollToPosition synchronously (blocked by b/114019007) mRecyclerView.post(new SmoothScrollToPosition(item, mRecyclerView)); } else { mRecyclerView.smoothScrollToPosition(item); } }



2021年3月4日木曜日

ViewPager2 の offscreenPageLimit のデフォルト値は 1 ではない。

ViewPager2 にも ViewPager と同様 offscreenPageLimit を指定することができます。

ViewPager2 の offscreenPageLimit のデフォルト値は 1 ではなく、ViewPager2.OFFSCREEN_PAGE_LIMIT_DEFAULT (= -1) です。

そのため FragmentStateAdapter を使っている場合、デフォルトでは隣の画面の Fragment はスワイプなどで表示が必要になるタイミングまで作成されません。
ViewPager と同じ挙動にするには、明示的に offscreenPageLimit に 1 を指定する必要があります。 val pager: ViewPager2 = ... pager.offscreenPageLimit = 1

2021年2月27日土曜日

ShapeDrawable + BitmapShader で elevation の影を出す

背景(background)の Drawable が ShapeDrawable の場合、elevation を指定すると影がでます。(1番目)
一方、BitmapDrawable では elevation を指定しても影がでません。(2番目)
しかし背景(background)の Drawable が BitmapDrawable でも ViewOutlineProvider を使うと影が出るようになります。(4番目) val provider = object : ViewOutlineProvider() { override fun getOutline(view: View, outline: Outline) { val radius = 32 * resources.displayMetrics.density outline.setRoundRect(0, 0, view.width, view.height, radius) } } findViewById<View>(R.id.frameLayout4).apply { outlineProvider = provider clipToOutline = true } ViewOutlineProvider を使わずに、ShapeDrawable と BitmapShader でも影がでるようにすることができます。(2番目) val r = 16 * resources.displayMetrics.density val shapeDrawable = ShapeDrawable( RoundRectShape(floatArrayOf(r, r, r, r, r, r, r, r), null, null) ) val bitmap = BitmapFactory.decodeResource(resources, R.drawable.image_round) shapeDrawable.shaderFactory = object: ShapeDrawable.ShaderFactory() { override fun resize(width: Int, height: Int): Shader { val bmp = bitmap.scale(width, height, false) return BitmapShader(bmp, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP) } } findViewById<View>(R.id.frameLayout2).background = shapeDrawable