自定义view/viewgroup/流布局(极简版)
来源:互联网 发布:尼古拉斯凯奇现状 知乎 编辑:程序博客网 时间:2024/04/30 01:38
1自定义view
1)构造器
private String text;private int mTitleTextSize;private Rect mBound;private Paint mPaint;public MyCuntomView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.MyCuntomView, defStyleAttr, defStyleRes);//自定义属性 int n = a.getIndexCount(); for (int i = 0; i < n; i++) { int attr = a.getIndex(i); switch (attr) { case R.styleable.CustomTitleView_titleText : text = a.getString(attr);//获得属性app:titleText="" break; case R.styleable.CustomTitleView_titleTextSize: // 默认设置为16sp,TypeValue也可以把sp转化为px //getDimensionPixelSize方法返回的是像素数值 //applyDimension转变为标准尺寸的一个函数 //getDisplayMetrics//1.0或者1.5 mTitleTextSize = a.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics())); Log.e("CustomTitleView: ", mTitleTextSize+""); break; } } a.recycle();//回收TypedArray //单击事件 this.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { mTitleText = "OnClick"; postInvalidate();//线程中刷新页面 } });}public MyCuntomView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr, 0);}public MyCuntomView(Context context, AttributeSet attrs) { this(context, attrs, 0, 0);}public MyCuntomView(Context context) { this(context, null, 0, 0);}
2)画图
@Overrideprotected void onDraw(Canvas canvas) { mPaint.setColor(Color.YELLOW); canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), mPaint);//画背景 mPaint.setColor(Color.BLACK); canvas.drawText(text, getWidth() / 2 - mBound.width() / 2, getHeight() / 2 + mBound.height() / 2, mPaint);//写字}
3)测量
@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){ int widthMode = MeasureSpec.getMode(widthMeasureSpec);//android:layout_width int widthSize = MeasureSpec.getSize(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec);//android:layout_height int heightSize = MeasureSpec.getSize(heightMeasureSpec); int width; int height; if (widthMode == MeasureSpec.EXACTLY) { //明确的值或者MATCH_PARENT width = widthSize; } else { //WARP_CONTENT mPaint.setTextSize(mTitleTextSize); mPaint.getTextBounds(mTitleText, 0, mTitleText.length(), mBound); width = mBound.width(); } if (heightMode == MeasureSpec.EXACTLY) { //明确的值或者MATCH_PARENT height = heightSize; } else { //WARP_CONTENT mPaint.setTextSize(mTitleTextSize); mPaint.getTextBounds(mTitleText, 0, mTitleText.length(), mBound); height = mBound.height(); } setMeasuredDimension(width, height);//设置测量结果}
2自定义viewgroup
1)generateLayoutParams
//ViewGroup能够支持margin即可,那么我们直接使用系统的MarginLayoutParams @Override public LayoutParams generateLayoutParams(AttributeSet attrs) { return new MarginLayoutParams(getContext(), attrs); }
2)构造器
public MyViewGroup(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes);}public MyViewGroup(Context context, AttributeSet attrs, int defStyle){ super(context, attrs, defStyle);}public MyViewGroup(Context context){ super(context);}public MyViewGroup(Context context, AttributeSet attrs){ super(context, attrs);}
3)onLayout子控件定位
//onLayout对其所有childView进行定位(设置childView的绘制区域)@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) { int cCount = getChildCount(); int cWidth = 0; int cHeight = 0; MarginLayoutParams cParams = null; /** * 遍历所有childView根据其宽和高,以及margin进行布局 */ for (int i = 0; i < cCount; i++) { View childView = getChildAt(i);//获得子控件 cWidth = childView.getMeasuredWidth(); cHeight = childView.getMeasuredHeight(); cParams = (MarginLayoutParams) childView.getLayoutParams(); int cl = 0, ct = 0, cr = 0, cb = 0; switch (i) { case 0://左上 cl = cParams.leftMargin; ct = cParams.topMargin; break; case 1://右上 cl = getWidth() - cWidth - cParams.leftMargin - cParams.rightMargin; ct = cParams.topMargin; break; } cr = cl + cWidth; cb = cHeight + ct; childView.layout(cl, ct, cr, cb);//确定位置 }}
4)onMeasure测量groupview宽高
//在onMeasure中计算childView的测量值以及模式,以及设置自己的宽和高:@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { //获得此ViewGroup上级容器为其推荐的宽和高,以及计算模式 int widthMode = MeasureSpec.getMode(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); int sizeWidth = MeasureSpec.getSize(widthMeasureSpec); int sizeHeight = MeasureSpec.getSize(heightMeasureSpec); // 计算出所有的childView的宽和高 measureChildren(widthMeasureSpec, heightMeasureSpec); //记录如果是wrap_content是设置的宽和高 int width = 0; int height = 0; int cCount = getChildCount(); int cWidth = 0; int cHeight = 0; MarginLayoutParams cParams = null; //根据childView计算的出的宽和高,以及设置的margin计算容器的宽和高,主要用于容器是 for (int i = 0; i < cCount; i++) { View childView = getChildAt(i); cWidth = childView.getMeasuredWidth(); cHeight = childView.getMeasuredHeight(); cParams = (MarginLayoutParams) childView.getLayoutParams(); if (i == 0 || i == 1) { width += cWidth + cParams.leftMargin + cParams.rightMargin; height = Math.max(height, cHeight); } } /** * 如果是wrap_content设置为我们计算的值 * 否则:直接设置为父容器计算的值 */ setMeasuredDimension((widthMode == MeasureSpec.EXACTLY) ? sizeWidth : width, (heightMode == MeasureSpec.EXACTLY) ? sizeHeight : height);}
3流布局
/** * Created by user on 16-6-12.流布局viewgroup */public class FloatTag extends ViewGroup { public FloatTag(Context context) { super(context); } public FloatTag(Context context, AttributeSet attrs) { super(context, attrs); } public FloatTag(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } public FloatTag(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); } //因为我们只需要支持margin @Override public LayoutParams generateLayoutParams(AttributeSet attrs) { return new MarginLayoutParams(getContext(), attrs); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); // 获得它的父容器为它设置的测量模式和大小 int sizeWidth = MeasureSpec.getSize(widthMeasureSpec); int sizeHeight = MeasureSpec.getSize(heightMeasureSpec); int modeWidth = MeasureSpec.getMode(widthMeasureSpec); int modeHeight = MeasureSpec.getMode(heightMeasureSpec); // 如果是warp_content情况下,记录宽和高 int width = 0; int height = 0; /** * 记录每一行的宽度,width不断取最大宽度 */ int lineWidth = 0; /** * 每一行的高度,累加至height */ int lineHeight = 0; int cCount = getChildCount(); for (int i = 0; i < cCount; i++) { View child = getChildAt(i); if (child.getVisibility() == View.GONE) { continue; } //测量每一个child的宽和高 measureChild(child, widthMeasureSpec, heightMeasureSpec); //得到child的布局参数 MarginLayoutParams layoutParams = (MarginLayoutParams) child.getLayoutParams(); //子控件宽高 int childWidth = child.getMeasuredWidth() + layoutParams.leftMargin + layoutParams.rightMargin; int childHeigt = child.getMeasuredHeight() + layoutParams.topMargin + layoutParams.bottomMargin; //换行 if (lineWidth + childWidth > sizeWidth) { width = Math.max(lineWidth, childWidth); lineWidth = childWidth; height += lineHeight; lineHeight = childHeigt; } else { lineWidth += childWidth; lineHeight = Math.max(lineHeight, childHeigt); } if (i == cCount - 1) { width = Math.max(lineWidth, sizeWidth); height += lineHeight; } } setMeasuredDimension((modeWidth == MeasureSpec.EXACTLY) ? sizeWidth : width, (modeHeight == MeasureSpec.EXACTLY) ? sizeHeight : height); } //onLayout中完成对所有childView的位置以及大小的指定 @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { int cCount = getChildCount(); int left = 0; int top = 0; int lineheight = 0; for (int i = 0; i < cCount; i++) { View child = getChildAt(i); if (child.getVisibility() == View.GONE) { continue; } MarginLayoutParams lp = (MarginLayoutParams) child .getLayoutParams(); if (left + lp.leftMargin + child.getWidth() > getWidth()) { left = lp.leftMargin; lineheight = Math.max(child.getHeight(), lineheight); top += lineheight; } else { left += lp.leftMargin; lineheight = Math.max(lineheight, child.getHeight()); } //计算childView的left,top,right,bottom int tc = top + lp.topMargin; int rc = left + child.getMeasuredWidth(); int bc = tc + child.getMeasuredHeight(); child.layout(left, tc, rc, bc); left += child.getWidth(); } }}
0 0
- 自定义view/viewgroup/流布局(极简版)
- Android 自定义View实现文本流布局
- 自定义控件(View viewGroup)
- 自定义view (一)自定义控件 viewGroup
- 自定义View绘制心得(自定义view和自定义viewGroup)
- 自定义View实例——FlowLayout(流布局)的实现
- Android 自定义View 入门——FlowLayout实例(流布局)
- android 自定义View——流布局FlowLayout
- 常用的自定义View例子一(流布式布局)
- Android自定义View(四)继承ViewGroup
- Android View体系(十一)自定义ViewGroup
- android 自定义 view 之ViewGroup(四)
- Android 自定义view(三) 继承ViewGroup
- android自定义View(viewGroup)
- 自定义View及ViewGroup
- 自定义view,viewgroup
- 自定义View,ViewGroup,SurfaceView
- 自定义View、ViewGroup
- html知识点
- Python库 资源 (Windows系统)
- css 3d
- Apache Httpd负载均衡Tomcat并实现Session Sticky和Session Cluster
- java值传递与引用传递
- 自定义view/viewgroup/流布局(极简版)
- 无显示器使用PC远程控制树莓派方案(有线&无线)
- 如何禁止listview的item项获得焦点,而让item的子控件获得焦点
- squid 反向WEB代理
- 通过losetup虚拟出块设备(文件系统)
- Android入门--获得屏幕分辨率
- Redis简介与安装
- springMVC 项目在jboss7中配置应用自己的log4j
- Loadrunner模拟JSON接口请求进行测试