カスタムView measureプロセスに関する基本的な考え方の整理

4649 ワード

『MeasureSpecの簡単な説明』という記事ではandroidにおけるViewのMeasureSpec測定方法について詳しく説明していますが、今日このブログではMeasureの測定について簡単にまとめています.本稿では,androidの一般的な測定法則をどのように自分のカスタムViewに適用するかに重点を置き,同時に指定に確定的な考え方を与える.これらの測定の内部の詳細についてはあまり説明しない.
実はMeasureには2つの具体的な状況があります.
1)測定が1つのViewであれば,Viewというクラスのmeasure(int widthMeasureSpec,int heightMeasureSpec)法により測定プロセスを完了することができる.
2)ViewGroupであればchildViewの測定を先に完了する必要があり,これは再帰的なプロセスである.childViewの幅と高さに基づいて、ListViewまたはGridViewのonMeasureメソッドなどの他の処理を行っています.
前述したように、viewのMeasureメソッドは、measureint widthMeasureSpec,int heightMeasureSpec)を呼び出し、中のパラメータに注意し、widthSpec/heightSpecに基づいて最終的にviewのサイズを決定します.我々がカスタマイズしたviewで測定が必要な場合は、viewのwidthSpecとheightSpecをそれぞれ取得する必要がある(注:説明の便宜上、widthSpecとheightSpecはすべてSpecで表される).『MeasureSpecの簡単な説明』で述べたように、Specを取得する方法は2つあります
a)ViewクラスのgetChildMeasureSpec(int spec,int padding,int childDimension)を呼び出してViewのSpecを取得する
・通常、最初のパラメータは、ViewのparentViewのspecを伝達する.ViewGroupmeasureChildメソッドはこのメソッドがどのように使用されるかの参考書と言えます.このメソッドは、childViewを測定するためにViewGroupが使用するときに呼び出されます.
    protected void measureChild(View child, int parentWidthMeasureSpec,  
                int parentHeightMeasureSpec) {  
            final LayoutParams lp = child.getLayoutParams();  
      
            final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,  
                    mPaddingLeft + mPaddingRight, lp.width);  
            final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,  
                    mPaddingTop + mPaddingBottom, lp.height);  
            //  child measure    
            child.measure(childWidthMeasureSpec, childHeightMeasureSpec);  
     }            

まずView GroupのSpecであるparentSpecを取得し、childViewのLayoutParamsの2つの情報を加えてgetChilMeasureSpecを呼び出してchildViewのSpecを取得し、Specが取得する以上、Viewクラスを呼び出す.measureメソッドはこのSpecをmeasureメソッドに渡して処理すればよい.
使用例:ListViewがItemViewを測定する際にItemViewのwidthSpecを取得するという考え方ですが、具体的にはmeasureScrapChildという方法では、関連コードは以下の通りです.
//  itemView LayoutParams
	   LayoutParams p = (LayoutParams) child.getLayoutParams();     
		//    
		if (p == null) {
            p = (AbsListView.LayoutParams) generateDefaultLayoutParams();
            child.setLayoutParams(p);
        }
        //      
		//   spec+chid layoutParams
        int childWidthSpec = ViewGroup.getChildMeasureSpec(widthMeasureSpec,
                mListPadding.left + mListPadding.right, p.width);

b)makeMeasureSpec(int size,int mode)メソッドによるViewのSpec値の取得
このメソッドはViewGroupクラスの静的メソッドであり、実際にgetChildMeasureSpecというメソッドは最後にmakeMeasureSpecを呼び出した!
使用例:ListView測定時にItemViewのheightSpecを取得するという考え方ですが、具体的にはmeasureScrapChildという方法では、関連コードは以下の通りです.
 int lpHeight = p.height;
        int childHeightSpec;
        if (lpHeight > 0) {
		    //        measureSpec     spec
            childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY);
        } else {
            childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
        }
aまたはbの2つの方法でViewのSpec値を取得した後、viewのmeasureメソッドを呼び出してviewの測定を行うことができます.具体的にはaまたはbを使用しますが、これは具体的なニーズに基づいて具体的に分析されています.固定的な要求はなく、ニーズに応じて柔軟に処理することができます.ListViewのItemViewに関する測定の完全なコードは以下の通りである.
	private void measureScrapChild(View child, int position, int widthMeasureSpec) {
       //  itemView LayoutParams
	   LayoutParams p = (LayoutParams) child.getLayoutParams();     
		//    
		if (p == null) {
            p = (AbsListView.LayoutParams) generateDefaultLayoutParams();
            child.setLayoutParams(p);
        }
        //      
		//   spec+chid layoutParams
        int childWidthSpec = ViewGroup.getChildMeasureSpec(widthMeasureSpec,
                mListPadding.left + mListPadding.right, p.width);
      
   	  int lpHeight = p.height;
        int childHeightSpec;
        if (lpHeight > 0) {
		    //        measureSpec     spec
            childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY);
        } else {
            childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
        }
		//  child     
        child.measure(childWidthSpec, childHeightSpec);
	
    }

だから上のビューの測定は総じて簡単です.
第一に、まずViewのSpec値を取得するだけでなく、具体的なSpecで得られた内部の詳細さえ必要ありません.第二に、Viewのmeasure値を呼び出す
得られたSpecはmeasureメソッドに伝えればよい.もちろん、必要であればsetMeasureDimension(int width,int height)を呼び出して、Viewの幅と高さを決定することができます.具体的な測定のルールは、異なるView Groupがレイアウトによって異なる測定ロジックを持っていますが、全体的な考え方は変わりませんが、測定は基本的にSpecの計算が欠かせません!
最後に、このmeasureのフレキシブルアプリケーションの使用例については、このブログを参照してください.このブログは主にmeasureChildrenメソッドを用いてすべてのChildViewを測定しています.measureChildrenメソッドは、実際にはmeasureChildメソッドをループ呼び出しています.