Android:屏幕适配总结

values-sw320dp是什么意思?

就是宽度位320dp

dp有多长

dp,是安卓开发用的单位,1dp表示在屏幕点密度为160dpi时1px长度。
160dpi的意思是,每英寸有160个像素点,像素点的间隔是2.54/160=15.8mm。

来台实际的pix机器看下:
sailfish:/ # wm size
Physical size: 1080x1920

sailfish:/ # wm density
Physical density: 420

屏幕分辨率是1080*1920,屏幕dpi是420,那么这个屏幕是多大尺寸呢?

首先计算对角线的像素数量:2202
尺寸=2202/420=5.2英寸

华为机器:
HWPCT:/ wm size Physical size: 1080x2310 HWPCT:/ wm density
Physical density: 480

xhdpi: 320dpi
hdpi: 240dpi
mdpi: 160dpi(baseline)
ldpi: 120dpi

参考:https://blog.csdn.net/walk_and_think/article/details/64920011

https://blog.csdn.net/weixin_33991727/article/details/91456406

怎么计算手机长宽对应的dp值?

例如pixel,长宽像素是1080 X 1920 px,屏幕密度是420dpi,

归一化的dip有哪些?

http://aospxref.com/android-7.1.2_r39/xref/frameworks/base/core/java/android/content/res/Configuration.java#1734

DialogFragment和Dialog的区别?

DialogFragment更先进一点

dialog嵌套ConstraintLayout,ConstraintLayout设置的大小不生效?

发现是使用了
View root = LayoutInflater.from(getContext()).inflate(getLayoutId(), null);的锅。
不过自定义dialog的确没有parent。只能这样子搞了。
参考:
https://www.jianshu.com/p/41796f541e67

推荐googlesample的实现
https://github.com/googlesamples/android-FingerprintDialog

dialog的根view是什么?

一般dialog不直接使用,而是使用AlertDialog。
根view是/frameworks/base/core/res/res/layout/alert_dialog.xml

一个dialog的创建流程是怎样的?

其实整个view都是在show方法里面创建的。
相当于show之前,只是设置了参数

    public void show() {

       //使用参数创建view
        if (!mCreated) {
            dispatchOnCreate(null);
        }

        //回调onStart
        onStart();
       //获取DecorView
        mDecor = mWindow.getDecorView();

        //ActionBar处理
        if (mActionBar == null && mWindow.hasFeature(Window.FEATURE_ACTION_BAR)) {
            final ApplicationInfo info = mContext.getApplicationInfo();
            mWindow.setDefaultIcon(info.icon);
            mWindow.setDefaultLogo(info.logo);
            mActionBar = new WindowDecorActionBar(this);
        }
        //获取window参数
        WindowManager.LayoutParams l = mWindow.getAttributes();
        
        if ((l.softInputMode
                & WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) == 0) {
            WindowManager.LayoutParams nl = new WindowManager.LayoutParams();
            nl.copyFrom(l);
            nl.softInputMode |=
                    WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
            l = nl;
        }
        //addView 触发绘制
        mWindowManager.addView(mDecor, l);
        mShowing = true;

        sendShowMessage();
    }

在AlertDialog中

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mAlert.installContent();
    }

最后调用到了AlertController中

    public void installContent() {
        int contentView = selectContentView();
        mWindow.setContentView(contentView);
        setupView();
    }

selectContentView代码如下

    private int selectContentView() {
        if (mButtonPanelSideLayout == 0) {
            return mAlertDialogLayout;
        }
        if (mButtonPanelLayoutHint == AlertDialog.LAYOUT_HINT_SIDE) {
            return mButtonPanelSideLayout;
        }
        // TODO: use layout hint side for long messages/lists
        return mAlertDialogLayout;
    }

mButtonPanelSideLayout是什么东西呢?
在AlertController的构造函数中创建的

    public AlertController(Context context, DialogInterface di, Window window) {
        final TypedArray a = context.obtainStyledAttributes(null,
                R.styleable.AlertDialog, R.attr.alertDialogStyle, 0);
        ..........
        mAlertDialogLayout = a.getResourceId(
                R.styleable.AlertDialog_layout, R.layout.alert_dialog);
        mButtonPanelSideLayout = a.getResourceId(
                R.styleable.AlertDialog_buttonPanelSideLayout, 0);
         ..........
    }

TypedArray又是什么鬼呢?
其实是自定义的属性值,参考
https://www.cnblogs.com/yydcdut/p/4251572.html

说明自己定义了一个属性,属性名就叫做alertDialogStyle


image.png

那么谁在布局文件用了这个属性呢?
搜索了一下,发现有这么多。


image.png

那究竟用的是哪个呢?这就相当于涉及到默认主题的问题了。
假设选择了AlertDialog.Material主题,看下他是怎么定义的?
在文件/frameworks/base/core/res/res/values/styles_material.xml中


image.png

可以看到定义了一些长宽高,还有布局等等。

如果是最普通的就是下面这样子的


image.png

这一句代码,相当于获取layout的属性
mAlertDialogLayout = a.getResourceId(
R.styleable.AlertDialog_layout, R.layout.alert_dialog);

对于AlertDialog.Material,有定义layout


image.png

而默认的则没有。

那我们用默认的来分析好了。默认的话相当于用的是R.layout.alert_dialog布局。
/frameworks/base/core/res/res/layout/alert_dialog.xml

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/parentPanel"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:paddingTop="9dip"
    android:paddingBottom="3dip"
    android:paddingStart="3dip"
    android:paddingEnd="1dip">

    <LinearLayout android:id="@+id/topPanel"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:minHeight="54dip"
        android:orientation="vertical">
        <LinearLayout android:id="@+id/title_template"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            android:gravity="center_vertical"
            android:layout_marginTop="6dip"
            android:layout_marginBottom="9dip"
            android:layout_marginStart="10dip"
            android:layout_marginEnd="10dip">
            <ImageView android:id="@+id/icon"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="top"
                android:paddingTop="6dip"
                android:paddingEnd="10dip"
                android:src="@drawable/ic_dialog_info" />
            <com.android.internal.widget.DialogTitle android:id="@+id/alertTitle"
                style="?android:attr/textAppearanceLarge"
                android:singleLine="true"
                android:ellipsize="end"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:textAlignment="viewStart" />
        </LinearLayout>
        <ImageView android:id="@+id/titleDivider"
            android:layout_width="match_parent"
            android:layout_height="1dip"
            android:visibility="gone"
            android:scaleType="fitXY"
            android:gravity="fill_horizontal"
            android:src="@android:drawable/divider_horizontal_dark" />
        <!-- If the client uses a customTitle, it will be added here. -->
    </LinearLayout>

    <LinearLayout android:id="@+id/contentPanel"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:orientation="vertical">
        <ScrollView android:id="@+id/scrollView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:paddingTop="2dip"
            android:paddingBottom="12dip"
            android:paddingStart="14dip"
            android:paddingEnd="10dip"
            android:overScrollMode="ifContentScrolls">
            <TextView android:id="@+id/message"
                style="?android:attr/textAppearanceMedium"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:padding="5dip" />
        </ScrollView>
    </LinearLayout>

    <FrameLayout android:id="@+id/customPanel"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1">
        <FrameLayout android:id="@+android:id/custom"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:paddingTop="5dip"
            android:paddingBottom="5dip" />
    </FrameLayout>

    <LinearLayout android:id="@+id/buttonPanel"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:minHeight="54dip"
        android:orientation="vertical" >
        <LinearLayout
            style="?android:attr/buttonBarStyle"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            android:paddingTop="4dip"
            android:paddingStart="2dip"
            android:paddingEnd="2dip"
            android:measureWithLargestChild="true">
            <LinearLayout android:id="@+id/leftSpacer"
                android:layout_weight="0.25"
                android:layout_width="0dip"
                android:layout_height="wrap_content"
                android:orientation="horizontal"
                android:visibility="gone" />
            <Button android:id="@+id/button1"
                android:layout_width="0dip"
                android:layout_gravity="start"
                android:layout_weight="1"
                style="?android:attr/buttonBarButtonStyle"
                android:maxLines="2"
                android:layout_height="wrap_content" />
            <Button android:id="@+id/button3"
                android:layout_width="0dip"
                android:layout_gravity="center_horizontal"
                android:layout_weight="1"
                style="?android:attr/buttonBarButtonStyle"
                android:maxLines="2"
                android:layout_height="wrap_content" />
            <Button android:id="@+id/button2"
                android:layout_width="0dip"
                android:layout_gravity="end"
                android:layout_weight="1"
                style="?android:attr/buttonBarButtonStyle"
                android:maxLines="2"
                android:layout_height="wrap_content" />
            <LinearLayout android:id="@+id/rightSpacer"
                android:layout_width="0dip"
                android:layout_weight="0.25"
                android:layout_height="wrap_content"
                android:orientation="horizontal"
                android:visibility="gone" />
        </LinearLayout>
     </LinearLayout>

妈耶,超长,不过细细看,就包含topPanel,contentPanel,customPanel,buttonPanel。

总结,最后可以看到系统的AlertDialog设置view的方式是通过
mWindow.setContentView(contentView);
而不是什么inflate!!!!!!!!!别用inflate了!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

AlertDialog的按键事件是怎么传递的?

app的写法如下


builder.setPositiveButton("当然是好看了!!", new DialogInterface.OnClickListener() {
    @Override
    public void onClick(DialogInterface dialog, int which) {
        Toast.makeText(AlertDialogActivity.this, "嘻嘻嘻",Toast.LENGTH_SHORT).show();
    }
});
builder.setNeutralButton("我觉得一般", new DialogInterface.OnClickListener() {
    @Override
    public void onClick(DialogInterface dialog, int which) {
        Toast.makeText(AlertDialogActivity.this,"那你再瞅瞅~",Toast.LENGTH_SHORT).show();
    }
});
builder.setNegativeButton("我觉得不好看", new DialogInterface.OnClickListener() {
    @Override
    public void onClick(DialogInterface dialog, int which) {
        Toast.makeText(AlertDialogActivity.this,"嘤嘤嘤",Toast.LENGTH_SHORT).show();
    }
});

mContentParent与decordView的关系是什么?

/frameworks/base/core/java/com/android/internal/policy/PhoneWindow.java
@Override
public void setContentView(int layoutResID) {
installDecor();
mLayoutInflater.inflate(layoutResID, mContentParent); //自定义布局的父视图是mContentParent

}

private void installDecor() {
        mDecor = generateDecor(-1);   //新建一个DecorView对象,其实是一个FrameLayout
        mContentParent = generateLayout(mDecor);
}

protected ViewGroup generateLayout(DecorView decor) {
    layoutResource = R.layout.screen_simple;   //decorView的布局
    mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);    //将布局inflate进来
    ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);  //找到id为ID_ANDROID_CONTENT的view
    return contentParent;
}

所以他的样子是如下图,图是源自这篇博客的:https://blog.csdn.net/guxiao1201/article/details/41744107

image.png

看看decorView的布局是怎么样的,以screen_simple为例子
http://androidxref.com/7.0.0_r1/xref/frameworks/base/core/res/res/layout/screen_simple.xml#3

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    android:orientation="vertical">
    <ViewStub android:id="@+id/action_mode_bar_stub"
              android:inflatedId="@+id/action_mode_bar"
              android:layout="@layout/action_mode_bar"
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:theme="?attr/actionBarTheme" />
    <FrameLayout
         android:id="@android:id/content"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:foregroundInsidePadding="false"
         android:foregroundGravity="fill_horizontal|top"
         android:foreground="?android:attr/windowContentOverlay" />
</LinearLayout>

下面是一个实际的例子,可以看到是一一对应上的。自定义布局的


image.png

参考:https://www.jianshu.com/p/c2b38bada5ba

ViewGroup测量流程是怎样的?

image.png

以下的布局:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="124dp"
        android:layout_marginLeft="124dp"
        android:text="查看定制dialog"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

setContentView直接用id的ConstraintLayout的参数

        View root = LayoutInflater.from(getContext()).inflate(getLayoutId(), null);
        setContentView(getLayoutId());
image.png

宽度为1050。

setContentView直接用view的ConstraintLayout的参数

        View root = LayoutInflater.from(getContext()).inflate(getLayoutId(), null);
        setContentView(root);
image.png

宽度为-1。

所以用inflate的方法的时候,如果没有传入parent,就出测量失效。

FrameLayout的测量代码如下

public class FrameLayout extends ViewGroup {


    public FrameLayout(@NonNull Context context) {
        super(context);
    }


    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int count = getChildCount();

        final boolean measureMatchParentChildren =
                MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.EXACTLY ||
                MeasureSpec.getMode(heightMeasureSpec) != MeasureSpec.EXACTLY;
        mMatchParentChildren.clear();

        int maxHeight = 0;
        int maxWidth = 0;
        int childState = 0;

        for (int i = 0; i < count; i++) {
            final View child = getChildAt(i);
            if (mMeasureAllChildren || child.getVisibility() != GONE) {
                measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);
            }
        }
    }
}

LayoutInflater的Inflater流程是怎样的?

以下面的布局为例子

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="400dp"
    android:layout_height="wrap_content">

    <TextView
        android:id="@+id/tv_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="18sp"
        android:layout_marginTop="19dp"
        android:layout_marginStart="19dp"
        android:layout_marginLeft="19dp"
        android:text="@string/naming_program"
        android:textColor="#242527"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/tv_message"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="#B3B4BA"
        android:textSize="15sp"
        android:layout_marginTop="18dp"
        android:layout_marginStart="19dp"
        android:layout_marginLeft="19dp"
        android:text="@string/naming_program_hint"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/tv_title" />

    <EditText
        android:id="@+id/et_input"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginLeft="16dp"
        android:layout_marginTop="8dp"
        android:inputType="text"
        android:textStyle="bold"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/tv_message" />

    <Button
        android:id="@+id/sure"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="12dp"
        android:layout_marginEnd="16dp"
        android:layout_marginRight="16dp"
        android:text="@string/sure"
        android:background="#ff7d8094"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/et_input" />

    <Button
        android:id="@+id/cancle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="12dp"
        android:layout_marginEnd="29dp"
        android:layout_marginRight="29dp"
        android:text="@string/cancel"
        android:background="#ffb3b4ba"
        app:layout_constraintEnd_toStartOf="@+id/sure"
        app:layout_constraintTop_toBottomOf="@+id/et_input" />

</androidx.constraintlayout.widget.ConstraintLayout>

代码如下

    public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) {
        synchronized (mConstructorArgs) {
            Trace.traceBegin(Trace.TRACE_TAG_VIEW, "inflate");

            final Context inflaterContext = mContext;
            final AttributeSet attrs = Xml.asAttributeSet(parser);
            Context lastContext = (Context) mConstructorArgs[0];
            mConstructorArgs[0] = inflaterContext;
            View result = root;

            try {
                // Look for the root node.
                int type;
                while ((type = parser.next()) != XmlPullParser.START_TAG &&
                        type != XmlPullParser.END_DOCUMENT) {
                    // Empty
                }

                if (type != XmlPullParser.START_TAG) {
                    throw new InflateException(parser.getPositionDescription()
                            + ": No start tag found!");
                }
               //找到TAG name,例如androidx.constraintlayout.widget.ConstraintLayout
                final String name = parser.getName(); 
                if (DEBUG) {
                    System.out.println("**************************");
                    System.out.println("Creating root view: "
                            + name);
                    System.out.println("**************************");
                }

                if (TAG_MERGE.equals(name)) {
                    if (root == null || !attachToRoot) {
                        throw new InflateException("<merge /> can be used only with a valid "
                                + "ViewGroup root and attachToRoot=true");
                    }

                    rInflate(parser, root, inflaterContext, attrs, false);
                } else {
                    // Temp is the root view that was found in the xml
                    final View temp = createViewFromTag(root, name, inflaterContext, attrs);

                    ViewGroup.LayoutParams params = null;

                    if (root != null) {
                        if (DEBUG) {
                            System.out.println("Creating params from root: " +
                                    root);
                        }
                        // Create layout params that match root, if supplied
                        params = root.generateLayoutParams(attrs);
                        if (!attachToRoot) {
                            // Set the layout params for temp if we are not
                            // attaching. (If we are, we use addView, below)
                            temp.setLayoutParams(params);
                        }
                    }

                    if (DEBUG) {
                        System.out.println("-----> start inflating children");
                    }

                    // Inflate all children under temp against its context.
                    //不断地Inflate 子组件,例如TextView
                    rInflateChildren(parser, temp, attrs, true);

                    if (DEBUG) {
                        System.out.println("-----> done inflating children");
                    }

                    // We are supposed to attach all the views we found (int temp)
                    // to root. Do that now.
                    if (root != null && attachToRoot) {
                        root.addView(temp, params);
                    }

                    // Decide whether to return the root that was passed in or the
                    // top view found in xml.
                    if (root == null || !attachToRoot) {
                        result = temp;
                    }
                }

            } catch (XmlPullParserException e) {
                final InflateException ie = new InflateException(e.getMessage(), e);
                ie.setStackTrace(EMPTY_STACK_TRACE);
                throw ie;
            } catch (Exception e) {
                final InflateException ie = new InflateException(parser.getPositionDescription()
                        + ": " + e.getMessage(), e);
                ie.setStackTrace(EMPTY_STACK_TRACE);
                throw ie;
            } finally {
                // Don't retain static reference on context.
                mConstructorArgs[0] = lastContext;
                mConstructorArgs[1] = null;

                Trace.traceEnd(Trace.TRACE_TAG_VIEW);
            }

            return result;
        }
    }
image.png

Inflater 产生的view的layout param是哪里来的?

在setContentView中来的


image.png

DecorView的layout param是在哪里赋值的?

在WindowManagerGlobal中

 public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow) {
            root = new ViewRootImpl(view.getContext(), display);
            view.setLayoutParams(wparams);  //在这里设置的
            mViews.add(view);
            mRoots.add(root);
            mParams.add(wparams);
            root.setView(view, wparams, panelParentView);
    }

DecorView的onMeasure是怎么执行的?

track如下图


image.png
    public static final int FILL_PARENT = -1;
    public static final int MATCH_PARENT = -1;
    public static final int WRAP_CONTENT = -2;
        layoutResource = R.layout.screen_simple;
        mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);

    void onResourcesLoaded(LayoutInflater inflater, int layoutResource) {
        final View root = inflater.inflate(layoutResource, null);
        addView(root, 0, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
    }

看上面的代码,可以知道layoutParam是MATCH_PARENT, MATCH_PARENT,跟xml里面写的布局也是一致的。

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    android:orientation="vertical">
    <ViewStub android:id="@+id/action_mode_bar_stub"
              android:inflatedId="@+id/action_mode_bar"
              android:layout="@layout/action_mode_bar"
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:theme="?attr/actionBarTheme" />
    <FrameLayout
         android:id="@android:id/content"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:foregroundInsidePadding="false"
         android:foregroundGravity="fill_horizontal|top"
         android:foreground="?android:attr/windowContentOverlay" />
</LinearLayout>

下面这句是整个测量的入口,看看参数都有什么

            // Ask host how big it wants to be
            windowSizeMayChange |= measureHierarchy(host, lp, res,
                    desiredWindowWidth, desiredWindowHeight);

lp是什么呢?
WindowManager.LayoutParams lp = mWindowAttributes;

Dialog的decorview的LayoutParams的长宽来源于哪里?

对于Dialog来说,这个params来源于show函数

   public void show() {
        WindowManager.LayoutParams l = mWindow.getAttributes();
        mWindowManager.addView(mDecor, l);
    }

在LayoutParams构造函数中,长宽的默认值是MATCH_PARENT,MATCH_PARENT

        public LayoutParams() {
            super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
            type = TYPE_APPLICATION;
            format = PixelFormat.OPAQUE;
        }

然后再generalLayout过程中,判断是floating窗口,然后设置成wrap_content

        if (mIsFloating) {
            setLayout(WRAP_CONTENT, WRAP_CONTENT);
            setFlags(0, flagsToUpdate);
        }

decorView的onMeasure的过程

入口如下:

            windowSizeMayChange |= measureHierarchy(host, lp, res,
                    desiredWindowWidth, desiredWindowHeight);

TypedValue是什么东西?

用来做dp和px转换的

MeasureSpec.AT_MOST和LayoutParams.MATCH_PARENT的关系?

AT_MOST是view的测量模式,MATCH_PARENT是你布局里面写的参数。
子view的测量模式是怎么来的呢?
其实是根据父view的测量模式和子view再布局里面写的参数决定的。代码如下

    public static int getChildMeasureSpec(int spec, int padding, int childDimension) {
        int specMode = MeasureSpec.getMode(spec);  //父view的参数
        int specSize = MeasureSpec.getSize(spec);

        int size = Math.max(0, specSize - padding);

        int resultSize = 0;
        int resultMode = 0;

        switch (specMode) {
        // Parent has imposed an exact size on us
        case MeasureSpec.EXACTLY:
            if (childDimension >= 0) {
                resultSize = childDimension;
                resultMode = MeasureSpec.EXACTLY;
            } else if (childDimension == LayoutParams.MATCH_PARENT) {
                // Child wants to be our size. So be it.
                resultSize = size;
                resultMode = MeasureSpec.EXACTLY;
            } else if (childDimension == LayoutParams.WRAP_CONTENT) {
                // Child wants to determine its own size. It can't be
                // bigger than us.
                resultSize = size;
                resultMode = MeasureSpec.AT_MOST;
            }
            break;

        // Parent has imposed a maximum size on us
        case MeasureSpec.AT_MOST:               //如果父view是wrapcontent
            if (childDimension >= 0) {   //子view给了特定的大小
                // Child wants a specific size... so be it
                resultSize = childDimension;
                resultMode = MeasureSpec.EXACTLY;
            } else if (childDimension == LayoutParams.MATCH_PARENT) { //子view是match parent
                // Child wants to be our size, but our size is not fixed.
                // Constrain child to not be bigger than us.
                resultSize = size;
                resultMode = MeasureSpec.AT_MOST;
            } else if (childDimension == LayoutParams.WRAP_CONTENT) { //子view是warp content
                // Child wants to determine its own size. It can't be
                // bigger than us.
                resultSize = size;
                resultMode = MeasureSpec.AT_MOST;
            }
            break;

        // Parent asked to see how big we want to be
        case MeasureSpec.UNSPECIFIED:
            if (childDimension >= 0) {
                // Child wants a specific size... let him have it
                resultSize = childDimension;
                resultMode = MeasureSpec.EXACTLY;
            } else if (childDimension == LayoutParams.MATCH_PARENT) {
                // Child wants to be our size... find out how big it should
                // be
                resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size;
                resultMode = MeasureSpec.UNSPECIFIED;
            } else if (childDimension == LayoutParams.WRAP_CONTENT) {
                // Child wants to determine its own size.... find out how
                // big it should be
                resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size;
                resultMode = MeasureSpec.UNSPECIFIED;
            }
            break;
        }
        //noinspection ResourceType
        return MeasureSpec.makeMeasureSpec(resultSize, resultMode);
    }

由上面的代码我们可以知道,如果父view是wrap content,如果子view没有设定特定的大小,则子view就是wrap content。这也其实可以理解。

子view的测量结果是怎么告诉父view的?

FrameLayout的重新测量逻辑是什么?

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343

推荐阅读更多精彩内容

  • Android屏幕适配总结 前言 目录 定义 使得某一元素在Android不同尺寸、不同分辨率的手机上具备相同的显...
    冰薄荷汽水阅读 600评论 0 4
  • 屏幕适配 屏幕适配的概念 碎片化既是 Android 的优势和弱点,也是开发者们头疼的问题,同时也为 Androi...
    s酸菜阅读 9,730评论 9 58
  • 前言 其实网上已经有很多人总结了Andorid 屏幕适配的知识. 这里总结了适配的主流方案, 通过分析思考适配的...
    章子_zz阅读 1,369评论 1 16
  • 开篇 近日,在研究屏幕适配的问题,由于涉及比较多概念,例如ppi、dpi、dip、px等等,在适配屏幕的时候经常不...
    炮八平五阅读 933评论 0 7
  • 一直以来对这个屏幕适配就比较含糊,今天,公司突然给安排了个任务要从原来的 1024 * 768的屏幕,适配到12...
    子丿龙阅读 1,150评论 1 3