LayoutManagerのプロセスをカスタマイズしますか?

3707 ワード

最近、Androidの毎日の知識グループに参加し、技術の漏れを補った.Androidは毎日
ちょうどカスタムLayoutManagerプロセスが見えますか?この問題は,これまでLayoutManagerのカスタム化が様々な効果をもたらすことを知っていたが,コードを引っ張って実践したことがない.この机会を借りて、勉强してみましょう.
参考ドキュメント:LayoutManagerの回転ギャラリーを作成し、カスタムRecyclerViewを参照してください.LayoutManager
最初の参考文書には詳細が明記されているので、私もそれに基づいて自分で一度やっただけで、コードは処理されず、流れだけを書いて、この知識点として記録します.
1.デフォルトのLayoutParamsオブジェクトを複写します.
generateDefaultLayoutParams().新しい継承クラスは書き直さなければなりません
2.複写子Viewの配置.
onLayoutChildren().各サブビューの配置位置を計算する必要があります.
  • はaddView()を介してRecyclerViewにViewを追加します.
  • measureChildWithMargins()は、viewのレイアウトを測定します.
  • layoutDecorated()は、viewを本当に対応する位置に配置します.

  • 3.RecyclerViewの水平または垂直スライドを許可する
  • canscrollVertically()またはcanscrollHorizontally()の2つのデフォルトはfalseであり、スライドは許可されません.
  • scrollVerticallyBy()は、全体スライド時のviewの回収表示を処理します.

  • 4.キャッシュを追加して高速多重化
    detachAndScrapAttachedViews()はすべて除去し、再追加(多重化)し、addView、measureChildWithMargins、layoutDecoratedでRecyclerViewに追加します.ここで使用する最も簡単な方法は、実際には、現在表示されている集合を作って、スライドに基づいて1つ追加すると、性能が高くなりますが、本質は同じで、多重化されています.
    遭遇した小さなピットは、RecyclerViewが高さのwrap_を設定しているためcontent、子Viewを表示できなくなり、match_に設定parentの可視化.理由:wrap_contentはLayoutManagerでonMeasure()の場合、そのmodeはAT_MOST.AT_MOSTはRecyclerViewにあります.onMeasure()の場合、defalutOnMeasure()を使用します.この関数は、高さの実際に取る最小値を取得し、miniHeight、padingtop padingbuttonを設定していないと、必ず0になります.これがwrap_contentが表示されない理由.
        void defaultOnMeasure(int widthSpec, int heightSpec) {
            // calling LayoutManager here is not pretty but that API is already public and it is better
            // than creating another method since this is internal.
            final int width = LayoutManager.chooseSize(widthSpec,
                    getPaddingLeft() + getPaddingRight(),
                    ViewCompat.getMinimumWidth(this));
            final int height = LayoutManager.chooseSize(heightSpec,
                    getPaddingTop() + getPaddingBottom(),
                    ViewCompat.getMinimumHeight(this));
    
            setMeasuredDimension(width, height);
        }
    
    
    public static int chooseSize(int spec, int desired, int min) {
                final int mode = View.MeasureSpec.getMode(spec);
                final int size = View.MeasureSpec.getSize(spec);
                switch (mode) {
                    case View.MeasureSpec.EXACTLY:
                        return size;
                    case View.MeasureSpec.AT_MOST:
                        return Math.min(size, Math.max(desired, min));
                    case View.MeasureSpec.UNSPECIFIED:
                    default:
                        return Math.max(desired, min);
                }
            }
    

    解決方法:LayoutManagerのonMeasureで、そのModeと高さを強制的に修正すればよい.変更内容:
        //LayoutManager.onMeasure()
        @Override
        public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state, int widthSpec, int heightSpec) {
            final int heightMode = View.MeasureSpec.getMode(heightSpec);
            int height = View.MeasureSpec.getSize(heightSpec);
    
            if (heightMode == View.MeasureSpec.AT_MOST) {
                if(totalHeight == 0){
                    for (int i = 0; i < getItemCount(); i++) {
                        View viewItem = recycler.getViewForPosition(i);
                        measureChildWithMargins(viewItem, 0, 0);
    
                        int w = getDecoratedMeasuredWidth(viewItem);
                        int h = getDecoratedMeasuredHeight(viewItem);
                        totalHeight +=h;
                    }
                }
                if(totalHeight< height){
                    height = totalHeight;
                }
                height = (height & ~(0x3 << 30)) | (View.MeasureSpec.EXACTLY & (0x3 << 30));
            }
            super.onMeasure(recycler, state, widthSpec, height);
    
        }