Android自定义View中padding与wrap_content的问题
来源:互联网 发布:webshell教程 编辑:程序博客网 时间:2024/05/29 18:03
很多时候,android系统提供的控件不能满足我们的业务需求,此时,需要我们自定义一个View,来展示我们的内容。
我们先来实现一个最简单的自定义View,画一个圆
package com.test.customview;import android.content.Context;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.support.annotation.Nullable;import android.util.AttributeSet;import android.view.View;public class CircleView extends View { private int mColor = Color.RED; private Paint mPaint; public CircleView(Context context) { this(context, null); } public CircleView(Context context, @Nullable AttributeSet attrs) { this(context, attrs, 0); } public CircleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } private void init() { mPaint = new Paint(); mPaint.setColor(mColor); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); int width = getWidth(); int height = getHeight(); int radius = Math.min(width, height) / 2; canvas.drawCircle(width / 2, height / 2, radius, mPaint); }}
在布局中使用它
<com.test.customview.CircleView android:layout_width="match_parent" android:layout_height="match_parent" />
看下效果
修改下布局,再看下效果,为了更明显看到控件大小,我们设置一个背景色
<com.test.customview.CircleView android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="#afafaf"/>
发现wrap_content并没有起作用,控件的高度依然是和父容器一样,这相当于match_parent
我们看下View中onMeasure的源码
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec), getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));}
看下getDefaultSize的实现:
public static int getDefaultSize(int size, int measureSpec) { int result = size; int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); switch (specMode) { case MeasureSpec.UNSPECIFIED: result = size; break; case MeasureSpec.AT_MOST: case MeasureSpec.EXACTLY: result = specSize; break; } return result; }
MeasureSpec代表一个32位的int值,高两位代表SpecMode ,是测量模式,低30位代表SpecSize ,是在某种测量模式下的规格大小。
SpecMode 有三种:
- UNSPECIFIED 父容器不对View做任何限制,一般用于系统内部
- AT_MOST 父容器指定一个可用大小SpecSize ,View不能大于这个值,对应LayoutParams中的wrap_content
EXACTLY 父容器已经测出View所需的精确大小,View的大小就是SpecSize ,对应LayoutParams的match_parent和具体数值这两中模式
可以看出,wrap_content和match_parent采用了同样的处理方式,会直接占满父容器的剩余空间。解决办法是重写onMeasure方法,并指定一个AT_MOST时的默认值
private int defaultWidth = 100;private int defaultHeight = 100;@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int widthSpaceMode = MeasureSpec.getMode(widthMeasureSpec); int widthSpaceSize = MeasureSpec.getSize(widthMeasureSpec); int heightSpaceMode = MeasureSpec.getMode(heightMeasureSpec); int heightSpaceSize = MeasureSpec.getSize(heightMeasureSpec); if (widthSpaceMode == MeasureSpec.AT_MOST && heightSpaceMode == MeasureSpec.AT_MOST) { setMeasuredDimension(defaultWidth, defaultHeight); } else if (widthSpaceMode == MeasureSpec.AT_MOST) { setMeasuredDimension(defaultWidth, heightSpaceSize); } else if (heightSpaceMode == MeasureSpec.AT_MOST) { setMeasuredDimension(widthSpaceSize, defaultHeight); }}
看下效果
wrap_content已经生效了
现在我们设置一个padding
<com.test.customview.CircleView android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="#afafaf" android:padding="10dp"/>
没有生效,处理也简单,在onDraw方法中,考虑到padding并进行相应处理即可
@Overrideprotected void onDraw(Canvas canvas) { super.onDraw(canvas); int paddingLeft = getPaddingLeft(); int paddingRight = getPaddingRight(); int paddingTop = getPaddingTop(); int paddingBottom = getPaddingBottom(); int width = getWidth() - paddingLeft - paddingRight; int height = getHeight() - paddingTop - paddingBottom; int radius = Math.min(width, height) / 2; canvas.drawCircle(paddingLeft + width / 2, paddingTop + height / 2, radius, mPaint);}
我们现在只有红色,如果想要画其他颜色的圆需要怎么办呢,Android中允许自定义属性来达到我们的目的
首先,在res/valus目录下新建attrs.xml值文件
新建一条自定义属性,比如说圆的颜色
<?xml version="1.0" encoding="utf-8"?><resources> <declare-styleable name="CircleView"> <attr name="circle_color" format="color"/> </declare-styleable></resources>
在CircleView中获取属性,在构造方法中调用
private void initAttrs(AttributeSet attrs) { TypedArray a = mContext.obtainStyledAttributes(attrs, R.styleable.CircleView); mColor = a.getColor(R.styleable.CircleView_circle_color, Color.RED); a.recycle();}
在布局文件中使用
<com.test.customview.CircleView android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="#afafaf" android:padding="10dp" app:circle_color="@color/colorPrimary"/>
成功
关于自定义属性中的format可以参考超级无敌宇宙传送门
完整代码:
package com.test.customview;import android.content.Context;import android.content.res.TypedArray;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.support.annotation.Nullable;import android.util.AttributeSet;import android.view.View;public class CircleView extends View { private Context mContext; private int mColor; private Paint mPaint; private int defaultWidth = 100; private int defaultHeight = 100; public CircleView(Context context) { this(context, null); } public CircleView(Context context, @Nullable AttributeSet attrs) { this(context, attrs, 0); } public CircleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); mContext = context; initAttrs(attrs); init(); } private void initAttrs(AttributeSet attrs) { TypedArray a = mContext.obtainStyledAttributes(attrs, R.styleable.CircleView); mColor = a.getColor(R.styleable.CircleView_circle_color, Color.RED); a.recycle(); } private void init() { mPaint = new Paint(); mPaint.setColor(mColor); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); int paddingLeft = getPaddingLeft(); int paddingRight = getPaddingRight(); int paddingTop = getPaddingTop(); int paddingBottom = getPaddingBottom(); int width = getWidth() - paddingLeft - paddingRight; int height = getHeight() - paddingTop - paddingBottom; int radius = Math.min(width, height) / 2; canvas.drawCircle(paddingLeft + width / 2, paddingTop + height / 2, radius, mPaint); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int widthSpaceMode = MeasureSpec.getMode(widthMeasureSpec); int widthSpaceSize = MeasureSpec.getSize(widthMeasureSpec); int heightSpaceMode = MeasureSpec.getMode(heightMeasureSpec); int heightSpaceSize = MeasureSpec.getSize(heightMeasureSpec); if (widthSpaceMode == MeasureSpec.AT_MOST && heightSpaceMode == MeasureSpec.AT_MOST) { setMeasuredDimension(defaultWidth, defaultHeight); } else if (widthSpaceMode == MeasureSpec.AT_MOST) { setMeasuredDimension(defaultWidth, heightSpaceSize); } else if (heightSpaceMode == MeasureSpec.AT_MOST) { setMeasuredDimension(widthSpaceSize, defaultHeight); } }}
- Android自定义View中padding与wrap_content的问题
- Android 自定义View之处理wrap_content,padding问题分析
- Android 自定义View时处理wrap_content和padding的方法
- Android 自定义View 适配wrap_content 和 padding 模板
- 自定义View设置padding和wrap_content无效的解决办法
- android-自定义View解决wrap_content无效的问题
- android-自定义View解决wrap_content无效的问题
- android-自定义View解决wrap_content无效的问题
- 自定义View的wrap_content属性失效问题详解
- 自定义View中onMeasure在wrap_content时的处理
- View中Margin与Padding的区别
- Android 中fill_parent与wrap_content的区别
- Android 中fill_parent与wrap_content的区别
- Android 中fill_parent与wrap_content的区别
- 为什么你的自定义View wrap_content不起作用?
- android自定义View之margin和padding的处理
- Android自定义View去除TextView的Padding值
- 自定义view支持wrap_content
- 关于Cannot send session cache limiter
- centos安装配置Tomcat
- Java SE基础及注意点
- 公司最新动态追踪
- 阿里云部署Java web项目初体验
- Android自定义View中padding与wrap_content的问题
- BZOJ 2342: [Shoi2011]双倍回文 manacher
- 将带有jni的Eclipse项目导入AndroidStudio遇到的问题
- 笔记——如何给JTextArea添加滚动条
- YUV格式详解
- 讨论子类和父类之间的关系
- STM32中的常量数组的首地址如何指定FLASH的某一个地址
- Selenium环境搭建
- Android UI系列之仿斗鱼滑动拼图验证码控件