前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >ViewGroup.LayoutParams 和 MeasureSpec

ViewGroup.LayoutParams 和 MeasureSpec

作者头像
全栈程序员站长
发布2022-09-13 13:37:06
4910
发布2022-09-13 13:37:06
举报
文章被收录于专栏:全栈程序员必看

大家好,又见面了,我是你们的朋友全栈君。

1.LayoutParams

LayoutParams 是ViewGroup的内部静态类 ,ViewGroup的子类(如RelativeLayout,LinearLayout,FrameLayout)都有其对应的 ViewGroup.LayoutParams的子类,如RelativeLayoutParams

LayoutParams 的作用:指定视图View 的高度(height) 和 宽度(width)等布局参数,具体如下:

参数

解释

具体值

dp / px

fill_parent

强制性使子视图的大小扩展至与父视图大小相等(不含 padding )

match_parent

与fill_parent相同,用于Android 2.3 & 之后版本

wrap_content

自适应大小,强制性地使视图扩展以便显示其全部内容(含 padding )

对应于xml如下:

android:layout_height=”wrap_content” //自适应大小 android:layout_height=”match_parent” //与父视图等高 android:layout_height=”fill_parent” //与父视图等高 android:layout_height=”20dp” //精确设置高度值为 20dp

下面是一个LinearLayoutParams的使用示例:

ViewGroup.LayoutParams 和 MeasureSpec
ViewGroup.LayoutParams 和 MeasureSpec

布局文件如下,只有一个TextView

代码语言:javascript
复制
<LinearLayout
    android:id="@+id/linear"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    xmlns:android="http://schemas.android.com/apk/res/android">
    <TextView
        android:layout_width="200dp"
        android:layout_height="30dp"
        android:text="第一个TextView"
        android:gravity="center"
        android:background="#6f00"
        />
</LinearLayout>

Activity代码如下:

代码语言:javascript
复制
public class MainActivity extends AppCompatActivity {

    private LinearLayout mRootView;
    private LinearLayout mLinearLayout;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mRootView = (LinearLayout) findViewById(R.id.linear);

        // 把 LinearLayout 添加到布局里面
        mLinearLayout = new LinearLayout(MainActivity.this);
        mLinearLayout.setBackgroundColor(Color.parseColor("#00ff00"));

        LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,LinearLayout.LayoutParams.WRAP_CONTENT);
        mLinearLayout.setLayoutParams(layoutParams);
        mRootView.addView(mLinearLayout);

        // 第二步,把TextView 添加到 LinearLayout,以增加一个TextView
        TextView textView = new TextView(MainActivity.this);
        textView.setText("第二个TextView");
        textView.setTextSize(20);
        textView.setBackgroundColor(Color.parseColor("#ff0000"));
        textView.setGravity(Gravity.CENTER);
        mLinearLayout.addView(textView);

        // 设置TextView大小为具体值
        LinearLayout.LayoutParams textParams = new LinearLayout.LayoutParams(textView.getLayoutParams());
        textParams.width = dip2px(MainActivity.this,200);
        textParams.height = dip2px(MainActivity.this,30);
        textView.setLayoutParams(textParams);

    }

    private int dip2px(Context context, float dipValue)
    {
        Resources r = context.getResources();
        return (int) TypedValue.applyDimension(
                TypedValue.COMPLEX_UNIT_DIP, dipValue, r.getDisplayMetrics());
    }


}

2.MeasureSpec

测量规格(MeasureSpec) = 测量模式(mode) + 测量大小(size)

ViewGroup.LayoutParams 和 MeasureSpec
ViewGroup.LayoutParams 和 MeasureSpec

其中,测量模式(Mode)的类型有3种:UNSPECIFIED、EXACTLY 和 AT_MOST。具体如下:

ViewGroup.LayoutParams 和 MeasureSpec
ViewGroup.LayoutParams 和 MeasureSpec

MeasureSpec 被封装在View类中的一个内部类里:MeasureSpec

MeasureSpec类 用1个变量封装了2个数据(size,mode)通过使用二进制,将测量模式(mode) & 测量大小(size)打包成一个int值来,并提供了如下的打包/解包的方法

/** * MeasureSpec类的具体使用 **/ //

获取测量模式(Mode) int specMode = MeasureSpec.getMode(measureSpec)

获取测量大小(Size) int specSize = MeasureSpec.getSize(measureSpec)

通过Mode 和 Size 生成新的SpecMode int measureSpec=MeasureSpec.makeMeasureSpec(size, mode);

MeasureSpec值的计算:子View的MeasureSpec值根据子View的布局参数(LayoutParams)和父容器的MeasureSpec值计算得来的,具体计算逻辑封装在getChildMeasureSpec(),即view的大小由父viewMeasureSpec值 和 子viewLayoutParams属性 共同决定。

/**

* 源码分析:getChildMeasureSpec()

* 作用:根据父视图的MeasureSpec & 布局参数LayoutParams,计算单个子View的MeasureSpec

* 注:子view的大小由父view的MeasureSpec值 和 子view的LayoutParams属性 共同决定

**/

public static int getChildMeasureSpec(int spec, int padding, int childDimension) {

//参数说明

* @param spec 父view的详细测量值(MeasureSpec)

* @param padding view当前尺寸的的内边距和外边距(padding,margin)

* @param childDimension 子视图的布局参数(宽/高)

//父view的测量模式

int specMode = MeasureSpec.getMode(spec);

//父view的大小

int specSize = MeasureSpec.getSize(spec);

//通过父view计算出的子view = 父大小–边距(父要求的大小,但子view不一定用这个值)

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

//子view想要的实际大小和模式(需要计算)

int resultSize = 0;

int resultMode = 0;

//通过父view的MeasureSpec和子view的LayoutParams确定子view的大小

// 当父view的模式为EXACITY时,父view强加给子view确切的值

//一般是父view设置为match_parent或者固定值的ViewGroup

switch (specMode) {

case MeasureSpec.EXACTLY:

// 当子view的LayoutParams>0,即有确切的值

if (childDimension >= 0) {

//子view大小为子自身所赋的值,模式大小为EXACTLY

resultSize = childDimension;

resultMode = MeasureSpec.EXACTLY;

// 当子view的LayoutParams为MATCH_PARENT时(-1)

} else if (childDimension == LayoutParams.MATCH_PARENT) {

//子view大小为父view大小,模式为EXACTLY

resultSize = size;

resultMode = MeasureSpec.EXACTLY;

// 当子view的LayoutParams为WRAP_CONTENT时(-2)

} else if (childDimension == LayoutParams.WRAP_CONTENT) {

//子view决定自己的大小,但最大不能超过父view,模式为AT_MOST

resultSize = size;

resultMode = MeasureSpec.AT_MOST;

}

break;

// 当父view的模式为AT_MOST时,父view强加给子view一个最大的值。(一般是父view设置为wrap_content)

case MeasureSpec.AT_MOST:

// 道理同上

if (childDimension >= 0) {

resultSize = childDimension;

resultMode = MeasureSpec.EXACTLY;

} else if (childDimension == LayoutParams.MATCH_PARENT) {

resultSize = size;

resultMode = MeasureSpec.AT_MOST;

} else if (childDimension == LayoutParams.WRAP_CONTENT) {

resultSize = size;

resultMode = MeasureSpec.AT_MOST;

}

break;

// 当父view的模式为UNSPECIFIED时,父容器不对view有任何限制,要多大给多大

// 多见于ListView、GridView

case MeasureSpec.UNSPECIFIED:

if (childDimension >= 0) {

// 子view大小为子自身所赋的值

resultSize = childDimension;

resultMode = MeasureSpec.EXACTLY;

} else if (childDimension == LayoutParams.MATCH_PARENT) {

// 因为父view为UNSPECIFIED,所以MATCH_PARENT的话子类大小为0

resultSize = 0;

resultMode = MeasureSpec.UNSPECIFIED;

} else if (childDimension == LayoutParams.WRAP_CONTENT) {

// 因为父view为UNSPECIFIED,所以WRAP_CONTENT的话子类大小为0

resultSize = 0;

resultMode = MeasureSpec.UNSPECIFIED;

}

break;

}

return MeasureSpec.makeMeasureSpec(resultSize, resultMode);

}

ViewGroup.LayoutParams 和 MeasureSpec
ViewGroup.LayoutParams 和 MeasureSpec

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/160854.html原文链接:https://javaforall.cn

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档