Android開発のgetMeasuredWidthとgetWidthの違いソースコードから分析
13609 ワード
関連記事:
Android開発のカスタムコントロール(一)---onMeasure詳細
Android開発のカスタムコントロール(二)---onLayout詳細
転載は出典を明記してください.http://blog.csdn.net/dmk877/article/details/49734869
私は多くの人がgetMeasuredWidthとgetWidthの方法(getMeasuredHeightとgetHeightに似ているここではgetMeasuredWidthとgetWidthだけを例に)に疑問を持っていると信じています.そして、ネット上で資料を調べても分からないような感じがします.ネット上の説明が間違っていることもあります.これを見ると、間違いがあると言う人が多いに違いありません.どうして人が間違っていると言ったの?どうして私たちにあなたの言うことが正しいと信じさせますか?この問題に対して、私が資料を調べ始めたとき、ネット上で「実際に画面が内容を包むことができるとき、彼らの値は等しい.viewが画面を超えたときだけ、彼らの違いがわかる.getMeasuredWidth()は実際のViewの大きさで、画面とは関係なく、getHeightの大きさは画面の大きさだ.画面を超えたときgetMeasuredWidth()getWidth()とスクリーン以外に表示されていない大きさに等しい」という答えを見たのは私だけではないと信じていましたが、その時はレベルが限られているので、上記の説を頭に入れましたが、勉強が進むにつれてこの説が正しくないことに気づきました.次に、ソースコードの観点から両者の違いとなぜ上の言い方が間違っているのかを詳しく分析し、見終わったら必ず収穫があると信じて、上記の2つの文章を読んでからこの文章を読むことを強くお勧めします.
誤りがあれば批判の指摘を歓迎し、疑問があれば伝言を歓迎する.
1、上記の観点の誤りを証明する
まず、どうして上のような言い方が間違っているのですか.例を見てみると、あなたは私の言い方に同意します.私の考えはこうです.
考え方:onWindowFocusChangedメソッドではコントロールが測定され、コントロールの幅と高さを取得することができ、画面の幅を超えるまでコントロールの幅と高さを変更することができます.getMeasuredWidthとgetWidthの値を印刷します.
コードは簡単にgetMeasuredWidthメソッドとgetWidthメソッドでコントロールの幅を取得して印刷します.コードは次のとおりです.
package com.example.customviewpractice;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.Window;
import android.widget.Button;
public class MainActivity extends Activity {
private Button btnTest;
private boolean isFocus=false;
@Override
protected void onCreate(Bundle savedInstanceState) {
requestWindowFeature(Window.FEATURE_NO_TITLE);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main1);
btnTest=(Button) findViewById(R.id.btn_test);
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if(!isFocus&&hasFocus){
Log.i("MainActivity","btnTest.getWidth="+btnTest.getWidth());
Log.i("MainActivity","btnTest.getMeasureWidth="+btnTest.getMeasuredWidth());
isFocus=true;
}
}
}
レイアウトファイルは次のとおりです.
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<Button
android:id="@+id/btn_test"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=" " />
</LinearLayout>
運転効果図は以下の通りです
印刷結果は次のとおりです.
プロパティがwrapである場合content時の幅は64(ここでの単位はpxであり、これは480*320のシミュレータであるこのとき1 dp=1 px)であり、このときgetWidthとgetMeasuredWidthの値は同じである.上記のレイアウトファイルのbtn_testの値を200 dpに設定した運転効果図は以下の通りです.
印刷結果は次のとおりです.
このときgetMeasuredWidthとgetWidthの値も同じですが、上記のように、Viewのサイズが画面のサイズを超えていなければ、この2つの値は同じで、間違いないように見えますが、レイアウトファイルのbtn_testの幅を1000 dpに変更しbtn_testが画面のサイズを超えた場合の実行効果は以下の通りです.
印刷結果は次のとおりです.
実行効果から、buttonの文字はもう見えないので、このときのbuttonは画面を超えていますが、印刷結果を見てみましょうか.相変わらず1000です.ここまで私が文章の冒頭を言うのは間違いです.皆さんは認めましたか?
2.getMeasuredWidthとgetWidthメソッドのソースコード分析
ではgetMeasuredWidthとgetWidthにはいったいどんな違いがあるのでしょうか.次に、ソースコードからこの2つの意味を詳しく分析します(注:ソースコードは2.3のソースコードを採用しています)
getMeasuredWidthメソッドのソースコード
/**
* The width of this view as measured in the most recent call to measure().
* This should be used during measurement and layout calculations only. Use
* {@link #getWidth()} to see how wide a view is after layout.
*
* @return The measured width of this view.
*/
public final int getMeasuredWidth() {
return mMeasuredWidth;
}
ここではその戻り値がmMeasuredWidthであることを見ていますが、このmMeasuredWidthはどこから来たのでしょうか.Androidが開発したカスタムコントロール(一)---onMeasureこのブログを詳しく理解した後、あなたはそれに慣れていないかもしれません.setMeasuredDimensionメソッドから伝達されたパラメータです.setMeasuredDimensionメソッドのソースコードを見てみましょう.
/**
* <p>This mehod must be called by {@link #onMeasure(int, int)} to store the
* measured width and measured height. Failing to do so will trigger an
* exception at measurement time.</p>
*
* @param measuredWidth the measured width of this view
* @param measuredHeight the measured height of this view
*/
protected final void setMeasuredDimension(int measuredWidth, int measuredHeight) {
mMeasuredWidth = measuredWidth;
mMeasuredHeight = measuredHeight;
mPrivateFlags |= MEASURED_DIMENSION_SET;
}
見たか?setMeasuredDimensionメソッドを呼び出すと、設定されたmeasuredWidthはここのmMeasuredWidth、つまり私たちのgetMeasuredWidthメソッドの戻り値であり、ここでmeasureメソッドが終了するとgetMeasuredWidthメソッドに値があることがわかります.getMeasuredWidthメソッドを解析した後、getWidthもソースコードを見てみましょう.
getWidthメソッドソースコード
/**
* Return the width of the your view.
*
* @return The width of your view, in pixels.
*/
@ViewDebug.ExportedProperty
public final int getWidth() {
return mRight - mLeft;
}
ソースコードからその戻り値がmRight-mLeft(Android開発のカスタムコントロール(二)---onLayout詳細ブログで詳しく説明されている)であることがわかりましたが、ここのmRightとmLeftはいったい何なのでしょうか.実はlayout過程から伝わってきた4つのパラメータのうちの2つなので、何を待っているのか見てみましょう.
layoutソース
public final void layout(int l, int t, int r, int b) {
boolean changed = setFrame(l, t, r, b);
if (changed || (mPrivateFlags & LAYOUT_REQUIRED) == LAYOUT_REQUIRED) {
if (ViewDebug.TRACE_HIERARCHY) {
ViewDebug.trace(this, ViewDebug.HierarchyTraceType.ON_LAYOUT);
}
onLayout(changed, l, t, r, b);
mPrivateFlags &= ~LAYOUT_REQUIRED;
}
mPrivateFlags &= ~FORCE_LAYOUT;
}
setFrameメソッドが呼び出されます.ソースコードは次のとおりです.
protected boolean setFrame(int left, int top, int right, int bottom) {
boolean changed = false;
if (mLeft != left || mRight != right || mTop != top || mBottom != bottom) {
changed = true;
。。。 。。。
mLeft = left;
mTop = top;
mRight = right;
mBottom = bottom;
。。。 。。。
}
return changed;
}
ここではgetWidthメソッドの戻り値の2つのパラメータ①mRight②mLeftを見つけた.これでgetWidthが値を返すことがわかりましたか?layoutメソッドの4つのパラメータがどこから来たのかと聞かれたら、読んでください(Android開発のカスタムコントロール(二)---onLayout詳細)と教えてあげます.ここまでgetWidthメソッドはlayoutメソッドが完了してからの値なので、カスタムコントロールの場合onLayoutメソッドではgetMeasuredWidthを使用してコントロールの幅を得るのが一般的です.getMeasuredWidthはmeasureの後に値があり、getWidthはlayoutで値があるからです.一方、onLayoutメソッドでgetMeasuredWidthメソッドを使用する以外の場所では、getWidthメソッドを使用してコントロールの幅を取得するのが一般的です.ソースコードの角度からgetMeasuredWidthとgetWidth方法を分析した後、私は学習中に出会った問題を共有し、ここで解答を分析します.
(1)getMeasuredWidthとgetWidthメソッドの戻り値が異なるようにするにはどうすればよいか.
この質問に答えるには、getMeasuredWidthの値はsetMeasuredDimensionメソッドで設定されていますが、getWidthの値はonLayoutメソッドで私たちが伝えた4つのパラメータです.setMeasuredDimensionメソッドで設定された幅値とonLayoutメソッドで渡されたmRight-mLeftの値が等しくない限り、印刷結果は異なります.そうでしょうか.私たちはコード検証を通じて最も説得力があり、私たちはView Groupをカスタマイズし、コードは以下の通りです.
package com.example.customviewpractice;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
public class MyViewGroup1 extends ViewGroup {
public MyViewGroup1(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, widthMeasureSpec);
View view = getChildAt(0);
/**
* 100,MeasureSpec.EXACTLY
*/
measureChild(view, MeasureSpec.EXACTLY + 50, MeasureSpec.EXACTLY + 100);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
View childView = getChildAt(0);
/**
* View ,
*/
childView.layout(0, 0, 200, 200);
}
}
上記では、ViewGroupのmeasureChildメソッドで設定されている幅は50であり、測定モードはEXACTLYである(Android開発のカスタムコントロール(一)---onMeasure詳細)に慣れていなければ読むことができ、layoutで設定されている幅は200-0=200である.同じくActivityのonWindowFocusChangedメソッドでgetWidthとgetMeasuredWidthの値を印刷します.
MainActivityのコードは次のとおりです.
package com.example.customviewpractice;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.Window;
import android.widget.Button;
public class MainActivity extends Activity {
private Button btn1;
private boolean isFocus=false;
@Override
protected void onCreate(Bundle savedInstanceState) {
requestWindowFeature(Window.FEATURE_NO_TITLE);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn1=(Button) findViewById(R.id.btn1);
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if(!isFocus&&hasFocus){
Log.i("MainActivity","btnTest.getWidth="+btn1.getWidth());
Log.i("MainActivity","btnTest.getMeasureWidth="+btn1.getMeasuredWidth());
isFocus=true;
}
}
}
レイアウトファイルは簡単です.カスタマイズされたView Groupの下にButtonを置きます.次のようにします.
<com.example.customviewpractice.MyViewGroup1 xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<Button
android:id="@+id/btn1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=" " />
</com.example.customviewpractice.MyViewGroup1>
運転後の効果図は以下の通りです
印刷結果は次のとおりです.
このときgetWidth=200は、layoutメソッドで渡された200-0、getMeasureWidth=50であり、setMeasuredDimensionメソッドで設定された値であるが、画面に表示されるのは確かに正方形であり、layout設定の幅200、高さ200である.しかし、この場合は非常に珍しく、ここでは効果を示すためにこのように書くのですが、一般的にgetMeasuredWidthとgetWidthメソッドの値は一致しています.ここでは、一般的にonLayoutメソッドでgetMeasuredWidthメソッドを呼び出す以外の場所でgetWidthメソッドを使えばよいことを覚えておけばいいのです.
(2)カスタムコントロールでonMeasureを書き換えてsuperを直接呼び出す.onMeasure(widthMeasureSpec,widthMeasureSpec)は、測定プロセスをデフォルトのプロセスで測定します.このようにすれば、onWindowFocusChanagedメソッドでgetMeasuredWidthメソッドを呼び出すと、値は0になりますか?どうして?
理由は簡単にsuperを呼び出すことです.onMeasure(widthMeasureSpec,widthMeasureSpec)メソッドは、onMeasureメソッドでsetMeasuredDimensionメソッドが呼び出され、mMinWidthが設定されていない場合は一般的に幅設定のデフォルト値が0になるのでgetMeasuredDimensionメソッドの戻りは0になります.これにより、getMeasuredWidthで値を取得するには、setMeasuredDimensionメソッドを1つのパスで呼び出す必要があります.そうしないと、一般的にgetMeasuredWidthの値は0になります.
3.まとめ
①getMeasuredWidthメソッドで得られた値はsetMeasuredDimensionメソッドで設定された値であり、その値はmeasureメソッドの実行後に決定される
②getWidthメソッドは、layoutメソッドで渡される4つのパラメータのうちのmRight-mLeftを取得します.その値はlayoutメソッドの実行後に決定されます.
③一般的にonLayoutメソッドではgetMeasuredWidthメソッドを用い,onLayoutメソッド以外の場所ではgetWidthメソッドを用いる.
もしあなたが文章の中に間違いがあることに気づいたら、批判を歓迎して、指摘して、私たちは一緒に進歩します.
もしあなたがこのブログがあなたに役に立つと感じたら、伝言あるいはトップになって、あなたの支持は私の前進の動力で、ガガ...
転載は出典を明記してください.http://blog.csdn.net/dmk877/article/details/49734869