Andoird 自定义ViewGroup
2016-06-24 17:19
253 查看
1.自定义ViewGroup
主要关注两点测量和布局:onMeasure
测量和保存各个视图和子视图的位置信息
onLayout
遍历所有子视图绘制
2.构造函数
1.res/values/attrs.xml自定义视图的属性
<?xml version="1.0" encoding="utf-8" ?> <resources> <declare-styleable name="CascadeLayout"> <attr name="horizontal_spacing" format="dimension" /> <attr name="vertical_spacing" format="dimension" /> </declare-styleable> </resources>
2.res/values/dimens.xml
自定义视图属性的默认值
<resources> <dimen name="horizontal_spacing">16dp</dimen> <dimen name="vertical_spacing">16dp</dimen> </resources>
java 代码中使用。
private int mHorizontalSpacing; private int mVerticalSpacing; public CascadeLayout(Context context, AttributeSet attributeSet) { super(context, attributeSet); TypedArray a = context.obtainStyledAttributes(attributeSet, R.styleable.CascadeLayout); try { mHorizontalSpacing = a.getDimensionPixelSize(R.styleable.CascadeLayout_horizontal_spacing, getResources().getDimensionPixelSize(R.dimen.horizontal_spacing)); mVerticalSpacing = a.getDimensionPixelSize(R.styleable.CascadeLayout_vertical_spacing, getResources().getDimensionPixelSize(R.dimen.vertical_spacing)); } finally { a.recycle(); } }
3. 布局 写法
自定义属性使用命名空间
a)eclipse写法,android studio也适用
类似系统自带属性命名空间 xmlns:android=”http://schemas.android.com/apk/res/android”
将res/android 换成你自定义view 所属的包名
xmlns:cascade=”http://schemas.android.com/apk/com.lq.viewpractice.viewgroup.CascadeLayout”
b)android studio写法,eclipse 不能用
使用res-auto
xmlns:cascade=”http://schemas.android.com/apk/res-auto”
引用lib 和自定义的view 都智能用res-auto
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:cascade="http://schemas.android.com/apk/com.lq.viewpractice.viewgroup.CascadeLayout" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.lq.viewpractice.ViewGroupTestActivity"> <com.lq.viewpractice.viewgroup.CascadeLayout android:layout_width="match_parent" android:layout_height="match_parent" cascade:horizontal_spacing="30dp" cascade:vertical_spacing="20dp"> <View android:layout_width="100dp" android:layout_height="150dp" android:background="#FF0000" /> <View android:layout_width="100dp" android:layout_height="150dp" android:background="#00FF00" /> <View android:layout_width="100dp" android:layout_height="150dp" android:background="#0000FF" /> </com.lq.viewpractice.viewgroup.CascadeLayout> </RelativeLayout>
4. 自定义LayoutParams
这个类的用途就是保存每个子视图的x,y轴位置。这里把它定义为静态内部类。public static class LayoutParams extends ViewGroup.LayoutParams { int x; int y; public int verticalSpacing; public LayoutParams(Context context, AttributeSet attrs) { super(context, attrs); } public LayoutParams(int w, int h) { super(w, h); } }
除此之外,还需要重写一些方法,checkLayoutParams()、generateDefaultLayoutParams()等,这个方法在不同ViewGroup之间往往是相同的。
@Override protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { return p instanceof LayoutParams; } @Override protected LayoutParams generateDefaultLayoutParams() { return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); } @Override public LayoutParams generateLayoutParams(AttributeSet attrs) { return new LayoutParams(getContext(), attrs); } @Override protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { return new LayoutParams(p.width, p.height); }
5. 核心代码 测量 onMeasure
测量子视图的坐标。@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int width = getPaddingLeft(); int height = getPaddingTop(); int verticalSpacing; final int count = getChildCount(); for (int i = 0; i < count; i++) { verticalSpacing = mVerticalSpacing; View child = getChildAt(i); measureChild(child, widthMeasureSpec, heightMeasureSpec); LayoutParams lp = (LayoutParams) child.getLayoutParams(); width = getPaddingLeft() + mHorizontalSpacing * i; //保存每个子视图的x,y轴坐标 lp.x = width; lp.y = height; if (lp.verticalSpacing >= 0) { verticalSpacing += lp.verticalSpacing; } width += width; height += verticalSpacing; } width += getPaddingRight(); height += getChildAt(getChildCount() - 1).getMeasuredHeight() + getPaddingBottom(); setMeasuredDimension(resolveSize(width, widthMeasureSpec), resolveSize(height, heightMeasureSpec)); }
6.核心代码 布局 onLayout
循环调用子view 布局。@Override protected void onLayout(boolean changed, int l, int t, int r, int b) { final int count = getChildCount(); for (int i = 0; i < count; i++) { View child = getChildAt(i); LayoutParams lp = (LayoutParams) child.getLayoutParams(); child.layout(lp.x, lp.y, lp.x + child.getMeasuredWidth(), lp.y + child.getMeasuredHeight()); } }
7. 参考链接
http://www.w2bc.com/Article/59242http://blog.csdn.net/manoel/article/details/39062737
8.demo地址
相关文章推荐
- bootstrap table 插件 从服务器请求数据 分页
- 【Android】关于Activity的生命周期及一些理解
- BlocksKit的使用
- Oracle创建存储过程、执行存储过程基本语法
- pyqt开发教程-搭建环境和开发示例
- android 调用支付宝充值,提示系统繁忙,4000
- static作用
- [转]使 Windows 下的 Qt 应用程序获得 Administrator 权限
- LuaJavaBridge - Lua 与 Java 互操作的简单解决方案
- 电脑桌面图标或者文件左下角出现蓝色问号解决办法
- Underscore.js 入门
- 类似问题 duplicate entry: com/example/apputils/BuildConfig.class
- haar detection demo code
- 定向爬取网页内容
- 回顾一学期的c++课程学习
- SMA、SMB、SMC封装的二极管尺寸区分
- 使用WebView实现离线阅读
- spring boot项目引用kaptcha
- Python中的__doc__
- android PixelFormat与ImageFormat的对比