自定义控件那些事儿 ----- 四【布局】
来源:互联网 发布:java字符串前后去空格 编辑:程序博客网 时间:2024/06/06 14:06
一、onLayout布局出洞
在上一篇文章自定义控件那些事儿 ------ 三【量测】中,为实现图片和文字组合控件的正确显示,就已经引入了onLayout实现的整体过程。
onLayout具体实现中,主要执行在layout()方法上。分别为left,top,right,bottom。实则是确定了当前控件的左上角和右下角,从而确定了当前控件展示的区域。所以,对一个View强制使用layout()方法,可以修改当前view所在的位置。在之后的属性动画实现中,就应用了这一特点。
达到理解整个布局过程作用,重写ViewGroup作为布局文件,其中内部子View均采用已有控件。从而避免较多的实现onMeasure()方法,导致整个过程的复杂。
二、初步实现
1,布局控件ViewGroup的实现
public class LayoutView extends ViewGroup { public LayoutView(Context context) { super(context); } public LayoutView(Context context, AttributeSet attrs) { super(context, attrs); } public LayoutView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override protected void onLayout(boolean b, int left, int top, int right, int bottom) { int tempHeight = 0; int mViewGroupWidth = getMeasuredWidth(); //当前ViewGroup的总宽度 int mPainterPosX = left; //当前绘图光标横坐标位置 int mPainterPosY = top; //当前绘图光标纵坐标位置 int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { View childView = getChildAt(i); int width = childView.getMeasuredWidth(); int height = childView.getMeasuredHeight(); if (height > tempHeight) { tempHeight = height; } //如果剩余的空间不够,则移到下一行开始位置 if (mPainterPosX + width > mViewGroupWidth) { mPainterPosX = left; mPainterPosY += tempHeight; } //执行ChildView的绘制 childView.layout(mPainterPosX, mPainterPosY, mPainterPosX + width, mPainterPosY + height); //记录当前已经绘制到的横坐标位置 mPainterPosX += width; } } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); measureChildren(widthMeasureSpec, heightMeasureSpec); }}
模仿LinearLayout的实现,做一个内部包含多个控件的控件。从左向右开始排列。当行距不够时,切换下一行显示。
注意点:
在类中使用tempHeight变量,用于记录当前行View的最高高度。换行以后的View只能在这个View之下,防止View之间的叠加。在换行中,要将tempHeight归零,第二行的高度不再以第一行的高度为最高值。
布局中使用:
<?xml version="1.0" encoding="utf-8"?><com.future.layoutdemo.view.LayoutView 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="com.future.layoutdemo.MainActivity"> <View android:layout_width="50dp" android:layout_height="50dp" android:background="@color/colorAccent" /> <View android:layout_width="180dp" android:layout_height="130dp" android:background="@color/colorPrimaryDark" /> <View android:layout_width="30dp" android:layout_height="80dp" android:background="@color/colorPrimary" /> <View android:layout_width="100dp" android:layout_height="100dp" android:background="@color/colorAccent" /> <View android:layout_width="200dp" android:layout_height="100dp" android:background="@color/colorPrimary" /></com.future.layoutdemo.view.LayoutView>
展示效果:
三、内容完善
在以上的实现中,添加margin值是没有效果的,当然不符合使用要求了!
1,修改控件实现,添加布局LayoutParams
在布局中优化布局计算,添加margin值影响。
public class Layout2View extends ViewGroup { public Layout2View(Context context) { super(context); } public Layout2View(Context context, AttributeSet attrs) { super(context, attrs); } public Layout2View(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override protected void onLayout(boolean b, int left, int top, int right, int bottom) { int tempHeight = 0; int mViewGroupWidth = getMeasuredWidth(); //当前ViewGroup的总宽度 int mViewGroupHeight = getMeasuredHeight(); //当前ViewGroup的总高度 int mPainterPosX = left; //当前绘图光标横坐标位置 int mPainterPosY = top; //当前绘图光标纵坐标位置 int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { View childView = getChildAt(i); int width = childView.getMeasuredWidth(); int height = childView.getMeasuredHeight(); if (height > tempHeight) { tempHeight = height; } Layout2View.LayoutParams margins = (Layout2View.LayoutParams) (childView.getLayoutParams()); //ChildView占用的width = width+leftMargin+rightMargin //ChildView占用的height = height+topMargin+bottomMargin //如果剩余的空间不够,则移到下一行开始位置 if (mPainterPosX + width + margins.leftMargin + margins.rightMargin > mViewGroupWidth) { mPainterPosX = left;// mPainterPosY += height + margins.topMargin + margins.bottomMargin; mPainterPosY += tempHeight + margins.topMargin + margins.bottomMargin; } //执行ChildView的绘制 childView.layout(mPainterPosX + margins.leftMargin, mPainterPosY + margins.topMargin, mPainterPosX + margins.leftMargin + width, mPainterPosY + margins.topMargin + height); mPainterPosX += width + margins.leftMargin + margins.rightMargin; } } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); measureChildren(widthMeasureSpec, heightMeasureSpec); } public static class LayoutParams extends ViewGroup.MarginLayoutParams { public LayoutParams(Context c, AttributeSet attrs) { super(c, attrs); } } @Override public LayoutParams generateLayoutParams(AttributeSet attrs) { return new Layout2View.LayoutParams(getContext(), attrs); }}
2,使用修改
<?xml version="1.0" encoding="utf-8"?><com.future.layoutdemo.view.Layout2View 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="com.future.layoutdemo.MainActivity"> <View android:layout_width="50dp" android:layout_height="50dp" android:layout_margin="20dp" android:background="@color/colorAccent" /> <View android:layout_width="180dp" android:layout_height="130dp" android:background="@color/colorPrimaryDark" /> <View android:layout_width="30dp" android:layout_height="80dp" android:background="@color/colorPrimary" /> <View android:layout_width="100dp" android:layout_height="100dp" android:layout_margin="10dp" android:background="@color/colorAccent" /> <View android:layout_width="200dp" android:layout_height="100dp" android:background="@color/colorPrimary" /></com.future.layoutdemo.view.Layout2View>
布局中添加margin值,展示效果如下:
源码传送门
慢慢的都会成长起来的,不管经历什么,不管有多少伤痛,你都能习惯的展示云淡风轻的微笑。
天塌下来,塞满食物的嘴里,再加一点鸡腿!
阅读全文
0 0
- 自定义控件那些事儿 ----- 四【布局】
- 自定义控件那些事儿 ----- 一
- 自定义控件那些事儿 ----- 二
- 3.4自定义控件的那些事儿~
- 自定义控件那些事儿 ----- 三【量测】
- 自定义控件那些事儿 ----- 五【绘制文字】
- 自定义控件那些事儿 ------ 六【绘制路径】
- 自定义控件那些事儿 ----- 七【绘制Bitmap】
- 自定义控件那些事儿 ----- 左滑删除控件
- 布局与控件(三)-TextView那些事儿
- 自定义控件那些事儿 ----- 八【着色器使用】
- 控件那些事儿
- WPF自定义控件那些事(四)
- DDR3布局的那些事儿
- 响应式布局那些事儿
- Ext2那些事儿(四)
- 线性布局LinearLayout的那些事儿
- 帧布局FrameLayout的那些事儿
- Window10+Ubuntu14.04双系统安装教程
- 纯CSS3动画之左右翻转
- 启动 Service 出现 Service Intent must be explicit 三种解决方法
- 集合总结
- Linux 学习 (六) (CentOS7)共享文件夹找不到怎么办
- 自定义控件那些事儿 ----- 四【布局】
- Spring 事务异常处理
- fixed针对于其他元素定位、父级
- Toast,popupWindow,AlertDialog
- phpstorm 配置 PHP_CodeSniffer
- 移动端相册开发
- linux笔记-1
- Session、Cookie理解及SSO(单点登录--cas)
- vue-devtools的安装与使用