使用 Android Studio自定义View01——注意是否重写onMeasure的区别,实现真正的自适应布局
来源:互联网 发布:淘宝油画 莫奈的花园 编辑:程序博客网 时间:2024/06/05 15:23
整理并总结自鸿洋的博客:http://blog.csdn.net/lmj623565791/article/details/24252901
一、不重写onMeasure,在res/layout/activity_main.xml中限定view的高度和宽度
com.cctvjiatao.customview01.act.MainActivity.java
/** * 自定义View 第一课 * 1、自定义View的属性 * 2、在View的构造方法中获得第1步中的自定义属性 * 3、重写onMeasure(这一步可省略) * 4、重写onDraw */public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); }}
res/values/attrs.xml
<?xml version="1.0" encoding="utf-8"?><resources> <attr name="title" format="string"/> <attr name="titleColor" format="color"/> <attr name="titleSize" format="dimension"/> <declare-styleable name="AuthCode"> <attr name="title"/> <attr name="titleColor"/> <attr name="titleSize"/> </declare-styleable></resources>
res/layout/activity_main.xml
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:authcode="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".act.MainActivity"> <com.cctvjiatao.customview01.view.AuthCode android:layout_width="200dp" android:layout_height="100dp" authcode:title="9527" authcode:titleColor="#ff0000" authcode:titleSize="40sp" /></RelativeLayout>
注意:在Android Studio中,使用的是xmlns:authcode="http://schemas.android.com/apk/res-auto",而在Eclipse中则应该使用xmlns:authcode="http://schemas.android.com/apk/res/com.cctvjiatao.customview01",即在res后的路径指向项目的package。
com.cctvjiatao.customview01.view.AuthCode.java
class AuthCode extends View { private String mTitle; private int mTitleColor; private int mTitleSize; private Rect mBound; private Paint mPaint; public AuthCode(Context context) { this(context, null); } public AuthCode(Context context, AttributeSet attrs) { this(context, attrs, 0); } public AuthCode(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); /* 获得自定义属性 */ TypedArray typedArray = context.getTheme().obtainStyledAttributes(attrs, R.styleable.AuthCode, defStyleAttr, 0); int a = typedArray.getIndexCount(); for (int i = 0; i < a; i++) { int attr = typedArray.getIndex(i); switch (attr) { case R.styleable.AuthCode_title: mTitle = typedArray.getString(attr); break; case R.styleable.AuthCode_titleColor: mTitleColor = typedArray.getColor(attr, Color.BLACK); break; case R.styleable.AuthCode_titleSize: mTitleSize = typedArray.getDimensionPixelSize(attr, (int) TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics())); break; } } typedArray.recycle(); /* 获得绘制的区域 */ mPaint = new Paint(); mPaint.setTextSize(mTitleSize); mBound = new Rect(); mPaint.getTextBounds(mTitle, 0, mTitle.length(), mBound); } /** * 调用系统的onMeasure,没有重写 */ @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); } /** * 重写onDraw */ @Override protected void onDraw(Canvas canvas) { mPaint.setColor(Color.YELLOW); canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), mPaint); mPaint.setColor(mTitleColor); canvas.drawText(mTitle, getWidth() / 2 - mBound.width() / 2, getHeight() / 2 + mBound.height() / 2, mPaint); }}
二、不重写onMeasure,在res/layout/activity_main.xml中自适应view的高度和宽度
修改res/layout/activity_main.xml代码如下:
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:authcode="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".act.MainActivity"> <com.cctvjiatao.customview01.view.AuthCode android:layout_width="wrap_content" android:layout_height="wrap_content" authcode:title="9527" authcode:titleColor="#ff0000" authcode:titleSize="40sp" /></RelativeLayout>
注意:把高度和宽度都修改成了 wrap_content
程序运行结果如图:
三、重写onMeasure,在res/layout/activity_main.xml中自适应view的高度和宽度,但不允许铺满全屏,实现真正的自适应
当设置了WRAP_CONTENT时,我们需要自己进行测量,即重写onMesure方法”,重写之前先了解MeasureSpec的specMode,一共三种类型:
EXACTLY:一般是设置了明确的值或者是MATCH_PARENT;
AT_MOST:表示子布局限制在一个最大值内,一般为WARP_CONTENT;
UNSPECIFIED:表示子布局想要多大就多大,很少使用;
在二的基础上继续修改com.cctvjiatao.customview01.view.AuthCode.java
package com.cctvjiatao.customview01.view;import android.content.Context;import android.content.res.TypedArray;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.Rect;import android.util.AttributeSet;import android.util.TypedValue;import android.view.View;import com.cctvjiatao.customview01.R;/** * Created by jiatao on 2016/6/4. */class AuthCode extends View { private String mTitle; private int mTitleColor; private int mTitleSize; private Rect mBound; private Paint mPaint; public AuthCode(Context context) { this(context, null); } public AuthCode(Context context, AttributeSet attrs) { this(context, attrs, 0); } public AuthCode(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); /* 获得自定义属性 */ TypedArray typedArray = context.getTheme().obtainStyledAttributes(attrs, R.styleable.AuthCode, defStyleAttr, 0); int a = typedArray.getIndexCount(); for (int i = 0; i < a; i++) { int attr = typedArray.getIndex(i); switch (attr) { case R.styleable.AuthCode_title: mTitle = typedArray.getString(attr); break; case R.styleable.AuthCode_titleColor: mTitleColor = typedArray.getColor(attr, Color.BLACK); break; case R.styleable.AuthCode_titleSize: mTitleSize = typedArray.getDimensionPixelSize(attr, (int) TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics())); break; } } typedArray.recycle(); /* 获得绘制的区域 */ mPaint = new Paint(); mPaint.setTextSize(mTitleSize); mBound = new Rect(); mPaint.getTextBounds(mTitle, 0, mTitle.length(), mBound); } /** * 重写onMeasure */ @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int widthMode = MeasureSpec.getMode(widthMeasureSpec); int widthSize = MeasureSpec.getSize(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec); int width, height; if (widthMode == MeasureSpec.EXACTLY) { width = widthSize; } else { mPaint.setTextSize(mTitleSize); mPaint.getTextBounds(mTitle, 0, mTitle.length(), mBound); width = (int) (getPaddingLeft() + mBound.width() + getPaddingRight()); } if (heightMode == MeasureSpec.EXACTLY) { height = heightSize; } else { mPaint.setTextSize(mTitleSize); mPaint.getTextBounds(mTitle, 0, mTitle.length(), mBound); height = (int) (getPaddingTop() + mBound.height() + getPaddingBottom()); } setMeasuredDimension(width, height); } /** * 重写onDraw */ @Override protected void onDraw(Canvas canvas) { mPaint.setColor(Color.YELLOW); canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), mPaint); mPaint.setColor(mTitleColor); canvas.drawText(mTitle, getWidth() / 2 - mBound.width() / 2, getHeight() / 2 + mBound.height() / 2, mPaint); }}
程序运行结果如图:
如果想美化显示,则修改res/layout/activity_main.xml即可,比如添加padding、居中等属性
继续修改res/layout/activity_main.xml
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:authcode="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=".act.MainActivity"> <com.cctvjiatao.customview01.view.AuthCode android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:padding="20dp" authcode:title="9527" authcode:titleColor="#ff0000" authcode:titleSize="40sp" /></RelativeLayout>
程序运行结果如图:
四、增加view的点击事件,使随机生成验证码
在三的基础上继续修改com.cctvjiatao.customview01.view.AuthCode.java
class AuthCode extends View { private String mTitle; private int mTitleColor; private int mTitleSize; private Rect mBound; private Paint mPaint; public AuthCode(Context context) { this(context, null); } public AuthCode(Context context, AttributeSet attrs) { this(context, attrs, 0); } public AuthCode(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); /* 获得自定义属性 */ TypedArray typedArray = context.getTheme().obtainStyledAttributes(attrs, R.styleable.AuthCode, defStyleAttr, 0); int a = typedArray.getIndexCount(); for (int i = 0; i < a; i++) { int attr = typedArray.getIndex(i); switch (attr) { case R.styleable.AuthCode_title: mTitle = typedArray.getString(attr); break; case R.styleable.AuthCode_titleColor: mTitleColor = typedArray.getColor(attr, Color.BLACK); break; case R.styleable.AuthCode_titleSize: mTitleSize = typedArray.getDimensionPixelSize(attr, (int) TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics())); break; } } typedArray.recycle(); /* 获得绘制的区域 */ mPaint = new Paint(); mPaint.setTextSize(mTitleSize); mBound = new Rect(); mPaint.getTextBounds(mTitle, 0, mTitle.length(), mBound); /* 添加点击事件 */ this.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { mTitle = randomTitle(); postInvalidate(); } }); } /** * 随机生成验证码 */ private String randomTitle() { Random random = new Random(); Set<Integer> set = new HashSet<Integer>(); while (set.size() < 4) { int i = random.nextInt(10); set.add(i); } StringBuffer sb = new StringBuffer(); for (Integer i : set) { sb.append(i + ""); } return sb.toString(); } /** * 重写onMeasure */ @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int widthMode = MeasureSpec.getMode(widthMeasureSpec); int widthSize = MeasureSpec.getSize(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec); int width, height; if (widthMode == MeasureSpec.EXACTLY) { width = widthSize; } else { mPaint.setTextSize(mTitleSize); mPaint.getTextBounds(mTitle, 0, mTitle.length(), mBound); width = (int) (getPaddingLeft() + mBound.width() + getPaddingRight()); } if (heightMode == MeasureSpec.EXACTLY) { height = heightSize; } else { mPaint.setTextSize(mTitleSize); mPaint.getTextBounds(mTitle, 0, mTitle.length(), mBound); height = (int) (getPaddingTop() + mBound.height() + getPaddingBottom()); } setMeasuredDimension(width, height); } /** * 重写onDraw */ @Override protected void onDraw(Canvas canvas) { mPaint.setColor(Color.YELLOW); canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), mPaint); mPaint.setColor(mTitleColor); canvas.drawText(mTitle, getWidth() / 2 - mBound.width() / 2, getHeight() / 2 + mBound.height() / 2, mPaint); }}
- 使用 Android Studio自定义View01——注意是否重写onMeasure的区别,实现真正的自适应布局
- Android自定义控件onMeasure方法简单的重写
- Android 自定义View onMeasure方法的实现
- android自定义View中onMeasure的使用
- 自定义view onMeasure方法的重写
- Android进阶——自定义View之View的绘制流程及实现onMeasure完全攻略
- 自定义viewgroup实现自动换行的布局,同时解决自定义布局在wrapcontent下高度不能自适应的问题,plus一些关于Component重写的基础知识
- 自定义的scrollview嵌套listview时重写onMeasure的原因
- Android中自定义View的onMeasure以及MeasureSpec使用
- Android流式布局FlowLayout的实现,Android布局的内部机制onMeasure、onLayout
- 自定义ViewGroup时,重写方法onMeasure等的说明
- iOS学习笔记-053.自定义View01——基础
- Android学习自定义View(五)——自定义ViewGroup及其onMeasure()的理解
- 重写View的onMeasure方法
- android构建自定义的视图组件onMeasure
- android构建自定义的视图组件onMeasure
- Android自定义控件的onMeasure和onLayout
- Android 自定义View 中的OnMeasure的用法
- 二分搜索树的实现
- 位操作总结
- 10.5.3 & 10.6节练习
- 智慧城市顶层设计范例:以数字家庭区块为例-P03
- 排序算法(3)-直接插入排序
- 使用 Android Studio自定义View01——注意是否重写onMeasure的区别,实现真正的自适应布局
- 面试算法总结
- 使用SQL Nexus整合----熟悉SQL Nexus
- Spring学习(十六)Spring Bean内容模型介绍
- Endless Punishment——HOJ
- leetcode-Java-202. Happy Number
- bzoj 1751 [Usaco2005 qua]Lake Counting
- SQL Server 2012内部原理及故障排除(专栏)
- 数据结构二叉树的递归遍历