大家好,又见面了,我是你们的朋友全栈君。
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的使用示例:
布局文件如下,只有一个TextView
<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代码如下:
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)
其中,测量模式(Mode)
的类型有3种:UNSPECIFIED、EXACTLY 和 AT_MOST。具体如下:
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
的大小由父view
的MeasureSpec
值 和 子view
的LayoutParams
属性 共同决定。
/**
* 源码分析: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);
}
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/160854.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...