XX, the works View (4) --- obtain measurements View width / height

Disclaimer: This article is a blogger original article, shall not be reproduced without the bloggers allowed. https://blog.csdn.net/yz_cfm/article/details/90760291

    View of the measure process of learning through the one, we know that, when the measure process is complete we can get to measure View width / height. But there is a problem is the measure and process life-cycle approach Activity of View is not synchronized execution, so we can not guarantee to get the accurate measurements View width / height in the Activity of a life cycle, provided below to learn about just brother the four methods:

    Method a: Activity / View # onWindowFocusChanged ()

    When this system is the callback method, indicating that View has been initialized, so this time we get width / height is no problem. This method will be the focus in the Activity window loses focus and calls, specifically, when the callback Activity onResume () - get the focus and onPause () - loses focus, this method will be called. Therefore typical code as follows:

@Override
public void onWindowFocusChanged(boolean hasFocus) {
    super.onWindowFocusChanged(hasFocus);

    if (hasFocus) {
        // Activity 的窗口得到焦点时调用
        int width = mCustomView.getMeasuredWidth();
        int height = mCustomView.getMeasuredHeight();
        Log.d("cfmtest", "customView 的宽度: " + width);
        Log.d("cfmtest", "customView 的高度: " + height);
    }
}

eg:

CustomView.java:

package com.cfm.viewtest;

public class CustomView extends View {

    public CustomView(Context context) {
        super(context);
    }

    public CustomView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public CustomView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);

        if(widthSpecMode == MeasureSpec.AT_MOST && heightSpecMode == MeasureSpec.AT_MOST){
            setMeasuredDimension(100, 100);
        }else if(widthSpecMode == MeasureSpec.AT_MOST && heightSpecMode == MeasureSpec.EXACTLY){
            setMeasuredDimension(100, heightSpecSize);
        }else if(widthSpecMode == MeasureSpec.EXACTLY && heightSpecMode == MeasureSpec.AT_MOST){
            setMeasuredDimension(widthSpecSize, 100);
        }
    }
}

MainActivity.java:

package com.cfm.viewtest;

public class MainActivity extends AppCompatActivity {

    private CustomView mCustomView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mCustomView = findViewById(R.id.custom_view);
    }

    @Override
    public void onWindowFocusChanged(boolean hasFocus) {
        super.onWindowFocusChanged(hasFocus);

        if (hasFocus) {
            int width = mCustomView.getMeasuredWidth();
            int height = mCustomView.getMeasuredHeight();
            Log.d("cfmtest", "customView 的宽度: " + width);
            Log.d("cfmtest", "customView 的高度: " + height);
        }
    }
}

activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    tools:context=".MainActivity">

    <com.cfm.viewtest.CustomView
        android:id="@+id/custom_view"
        android:background="@color/colorPrimary"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

</LinearLayout>

Print Log Information:

2019-05-30 22:31:24.088 9057-9057/com.cfm.viewtest D/cfmtest: customView 的宽度: 100
2019-05-30 22:31:24.088 9057-9057/com.cfm.viewtest D/cfmtest: customView 的高度: 100

    Method two: view.post (runnable)

    A runnable can be delivered by post to the end of the message queue, and then wait for the call this time Looper of runnable, View has also been initialized good. Typical code is as follows:

@Override
protected void onStart() {
    super.onStart();

    mCustomView.post(new Runnable() {
        @Override
        public void run() {
            int width = mCustomView.getMeasuredWidth();
            int height = mCustomView.getMeasuredHeight();
        }
    });
}

eg:

MainActivity.java:

package com.cfm.viewtest;

public class MainActivity extends AppCompatActivity {

    private CustomView mCustomView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mCustomView = findViewById(R.id.custom_view);
    }

    @Override
    protected void onStart() {
        super.onStart();
        mCustomView.post(new Runnable() {

            @Override
            public void run() {
                int width = mCustomView.getMeasuredWidth();
                int height = mCustomView.getMeasuredHeight();
                Log.d("cfmtest", "customView 的宽度: " + width);
                Log.d("cfmtest", "customView 的高度: " + height);
            }
        });
    }
}

Print Log Information:

2019-05-30 22:42:18.147 11187-11187/com.cfm.viewtest D/cfmtest: customView 的宽度: 100
2019-05-30 22:42:18.147 11187-11187/com.cfm.viewtest D/cfmtest: customView 的高度: 100

    Method three: ViewTreeObserver

    Use ViewTreeObserver many callbacks can be completed. OnGlobalLayoutListener such as using this interface, the visibility is changed when a state change occurs Tree View or internal tree View, View, onGlobalLayout () will be called back. It should be noted that, with the state View tree changes, etc., onGlobalLayout () may be called multiple times. Typical code is as follows:

@Override
protected void onStart() {
    super.onStart();

    ViewTreeObserver observer = mCustomView.getViewTreeObserver();
    observer.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {

        @Override
        public void onGlobalLayout() {
            // 防止多次调用
            mCustomView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
            int width = mCustomView.getMeasuredWidth();
            int height = mCustomView.getMeasuredHeight();
        }
    });
}

eg:

MainActivity.java:

package com.cfm.viewtest;

public class MainActivity extends AppCompatActivity {
    private CustomView mCustomView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mCustomView = findViewById(R.id.custom_view);
    }

    @Override
    protected void onStart() {
        super.onStart();
        ViewTreeObserver observer = mCustomView.getViewTreeObserver();
        observer.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {

            @Override
            public void onGlobalLayout() {
                mCustomView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                int width = mCustomView.getMeasuredWidth();
                int height = mCustomView.getMeasuredHeight();
                Log.d("cfmtest", "customView 的宽度: " + width);
                Log.d("cfmtest", "customView 的高度: " + height);
            }
        });
    }
}

Print Log Information:

2019-05-30 22:50:25.848 12869-12869/com.cfm.viewtest D/cfmtest: customView 的宽度: 100
2019-05-30 22:50:25.848 12869-12869/com.cfm.viewtest D/cfmtest: customView 的高度: 100

    方法四: view.measure(int widthMeasureSpec, int heightMeasureSpec)

    Obtained by View View be manually measure the width and height. Reference View of MeasureSpec, Points to consider:

    Case 1:

    When the View of LayoutParams is match_parent:

    By the above table, it is known, at this time may be EXACTLY SpecMode View, or AT_MOST (particularly by the parent container MeasureSpec be determined), and is SpecSize parentSize, i.e. the size of the remaining space parent container. And this time, we can not know the size of parentSize, so in theory can not measure the size of the View.

    Case 2:

    When View LayoutParams for a single value (dp / pc):

    According to the above table we can know, View of SpecMode is EXACTLY mode, SpecSize LayoutParams specific value of View. Therefore typical code as follows:

// eg: View 的 LayoutParams 中宽/高都为 100px
int widthMeasureSpec = MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY);
int heightMeasureSpec = MeasureSpec.makeMeasureSpec(100, MeasureSpec.EXACTLY);
view.measure(widthMeasureSpec, heightMeasureSpec);

    Case 3:

    When the View of LayoutParams is wrap_content:

    It can be seen by the table, for the case SpecMode AT_MOST, and the maximum value is SpecSize parentSize. Then we use the maximum SpecSize to create MeasureSpec, typical code is as follows:

int widthMeasureSpec = MeasureSpec.makeMeasureSpec((1 << 30) - 1, MeasureSpec.AT_MOST);
int heightMeasureSpec = MeasureSpec.makeMeasureSpec((1 << 30) - 1, MeasureSpec.AT_MOST);
view.measure(widthMeasureSpec, heightMeasureSpec);

eg:

MainActivity.java:

package com.cfm.viewtest;

public class MainActivity extends AppCompatActivity {
    private CustomView mCustomView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mCustomView = findViewById(R.id.custom_view);
    }

    @Override
    protected void onStart() {
        super.onStart();
        int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(200, View.MeasureSpec.EXACTLY);
        int  heightMeasureSpec = View.MeasureSpec.makeMeasureSpec((1<<30)-1, View.MeasureSpec.AT_MOST);
        mCustomView.measure(widthMeasureSpec, heightMeasureSpec);
        Log.d("cfmtest", "customView 的宽度: " + mCustomView.getMeasuredWidth());
        Log.d("cfmtest", "customView 的高度: " + mCustomView.getMeasuredHeight());
    }
}

activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    tools:context=".MainActivity">

    <com.cfm.viewtest.CustomView
        android:id="@+id/custom_view"
        android:background="@color/colorPrimary"
        android:layout_width="200dp"
        android:layout_height="wrap_content"/>

</LinearLayout>

Print Log Information:

2019-05-31 19:29:58.122 9170-9170/com.cfm.viewtest D/cfmtest: customView 的宽度: 200
2019-05-31 19:29:58.122 9170-9170/com.cfm.viewtest D/cfmtest: customView 的高度: 100

 

Guess you like

Origin blog.csdn.net/yz_cfm/article/details/90760291