自定义控件-CascadeLayout
来源:互联网 发布:常见的网络进攻形式 编辑:程序博客网 时间:2024/06/11 23:39
(1)前言
android的进阶之路上,总少不了使用自定义控件。自定义控件按照不同的分法,有不同的分类,这里主要分为四类:
1 继承自view,重写 onDraw方法;比如系统的TextView,ImageView
2 继承自ViewGroup,实现自己的自定义控件;
3 继承自特定的view(比如ImageView),
圆角图片CircleImageView,自带清除按钮的EditText
4 继承自特定的ViewGroup,(比如LinearLayout,ListView)自定义控件-下拉刷新和上拉加载的listView
view的工作流程是measure,layout和draw三大流程,也就是测量,布局和绘制,通过这三大步骤来完成这个view的布局以及显示。大多数时候我们都会选择后两种实现自定义控件,因为我们的一些系统控件已经帮我们处理好了各种测绘流程。今天来实现第2种。继承自ViewGroup,实现自己的自定义控件来实现如图所示的效果。很简单的自定义控件,但是对于了解和使用自定义控件有很大的帮助。
(2) 界面布局:
首先了解怎么使用,有个整体概念。
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:cascade="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_gravity="center" android:layout_height="match_parent"> <com.nsu.edu.cascadelayout.CascadeLayout android:layout_width="fill_parent" android:layout_height="fill_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.nsu.edu.cascadelayout.CascadeLayout></FrameLayout>
3 在attrs 定义自定义属性
<?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>
注意在androidStudio中我们使用自定义属性的时候命名空间为:xmlns:cascade=”http://schemas.android.com/apk/res-auto”
4 在dimens.xml中添加自定义属性的默认值
<resources> <!-- Default screen margins, per the Android Design guidelines. --> <dimen name="activity_horizontal_margin">16dp</dimen> <dimen name="activity_vertical_margin">16dp</dimen> <dimen name="cascade_horizontal_spacing">10dp</dimen> <dimen name="cascade_vertical_spacing">10dp</dimen> </resources>
5 自定义控件布局继承自ViewGroup
package com.nsu.edu.cascadelayout; import android.content.Context; import android.content.res.TypedArray; import android.util.AttributeSet; import android.view.View; import android.view.ViewGroup; /** * Created by Anthony on 2016/1/28. * Class Note:自定义控件实现叠加效果 */ public class CascadeLayout extends ViewGroup { private int horizontalSpacing; private int verticalSpacing; public CascadeLayout(Context context) { this(context, null); } public CascadeLayout(Context context, AttributeSet attrs) { this(context, attrs, 0); } /** *step1 从自定义属性中获取,如果其值没有指定,则使用默认值 */ public CascadeLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CascadeLayout); horizontalSpacing = a.getDimensionPixelSize(R.styleable.CascadeLayout_horizontal_spacing , getResources().getDimensionPixelSize(R.dimen.cascade_horizontal_spacing)); verticalSpacing = a.getDimensionPixelSize(R.styleable.CascadeLayout_vertical_spacing, getResources().getDimensionPixelSize(R.dimen.cascade_vertical_spacing)); a.recycle(); } /** * step2 自定义LayoutParams ,该类用于保存每个子视图的x,y轴位置 */ public class LayoutParams extends ViewGroup.LayoutParams { int x; int y; public LayoutParams(Context c, AttributeSet attrs) { super(c, attrs); } public LayoutParams(int width, int height) { super(width, height); } public LayoutParams(ViewGroup.LayoutParams source, int x, int y) { super(source); this.x = x; this.y = y; } } /** * step3 使用自定义LayoutParams必须重写下面的四个方法 */ @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); } /** * step4 重写onMeasure */ @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { //使用宽和高计算布局的最终大小以及子视图的x和y轴位置 int width = 0; int height = getPaddingTop(); //获取每个子视图 final int count = getChildCount(); for (int i = 0; i < count; i++) { View child = getChildAt(i); //让每个子视图测量自身 measureChild(child, widthMeasureSpec, heightMeasureSpec); //获取每个子视图的LayoutParams LayoutParams lp = (LayoutParams) child.getLayoutParams(); width = getPaddingLeft() + horizontalSpacing * i; lp.x = width; lp.y = height;//将宽和高保存到自定义的LayoutParams中去 width += child.getMeasuredWidth(); height += verticalSpacing; } //使用计算所得的宽和高设置整个布局的测量尺寸 width += getPaddingRight(); height += getChildAt(getChildCount() - 1).getMeasuredHeight() + getPaddingBottom(); // resolveSize的主要作用就是根据你提供的大小和MeasureSpec, // 返回你想要的大小值,这个里面根据传入模式的不同来做相应的处理 setMeasuredDimension(resolveSize(width, widthMeasureSpec), resolveSize(height, heightMeasureSpec)); } /** *step 5 重写onLayout */ @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()); } } }
步骤:
step1 构造函数中,从自定义属性中获取,如果其值没有指定,则使用默认值
step2 自定义LayoutParams ,该类用于保存每个子视图的x,y轴位置
step3 使用自定义LayoutParams必须重写下面的四个方法
step4 重写onMeasure
step 5 重写onLayout
继承ViewGroup不需要重写onDraw
本项目github地址:https://github.com/CameloeAnthony/CascadeLayout
- 自定义控件-CascadeLayout
- 自定义控件-CascadeLayout
- 自定义控件之CascadeLayout(一)
- 自定义控件之CascadeLayout(二)
- 自定义控件之--CascadeLayout(三)
- 自定义View之 CascadeLayout
- 自定义ViewGroup--CascadeLayout
- android自定义层级view,扑克牌堆叠效果,cascadeLayout
- 自定义控件
- 自定义控件
- 自定义控件
- 自定义控件
- 自定义控件
- 自定义控件
- 自定义控件
- 自定义控件
- 自定义控件
- 自定义控件
- atrDialong 弹窗使用下载
- Redis主从复制
- 使用JAVA转换符实现Android日期时间
- MIT 6.828 学习笔记2 阅读main.c
- gen_server + ets的几个小技巧
- 自定义控件-CascadeLayout
- Ubuntu14.04 Vxlan实验
- CF 467A George and Accommodation
- SpringMVC 400 Bad Request 问题解决
- lunix常用命令和技巧(Red Hat Enterprise Linux Server release 6.2)
- React学习2
- LeetCode(56)-Add Binary
- 部分和问题升级版
- 一张图看懂收录与索引的区别