Android自定义view
来源:互联网 发布:lol安妮舞会公主淘宝 编辑:程序博客网 时间:2024/06/03 21:49
自定义View是每个Android开发人员的必备技能,首先我们先来看一下自定义view的几个步骤:
1、自定义属性
2、在构造函数中获取自定义属性
3、重写onMeasure() [非必须]
4、重写onDraw()
对于自定义view并不是每个自定义View都必须重写onMeasure方法,当然绝大多数时候我们还是需要重写这个方法。
下面我们分别来看下这几个步骤:
1、自定义属性:
<?xml version="1.0" encoding="utf-8"?><resources> <attr name="titleTextColor" format="color"/> <attr name="titleTextSize" format="dimension"/> <attr name="titleText" format="string"/> <declare-styleable name="CustomTextView"> <attr name="customTitleText" format="string"/> <attr name="customTitleTextColor" format="color"/> <attr name="custonTitleTextSize" format="dimension"/> </declare-styleable></resources>
在这里我们现在res/values 的文件下下新建一个attrs.xml,然后我们在这个文件里面定义了文字、文字大小、文字颜色三个属性,format是指属性的类型一共有10个:string、color、integer、dimession、enum、reference(参考某一资源id)、boolean、float、fraction(百分数)、flag
(1)、 string:字符串
属性定义:
<declare-styleable name="CustomTextView"> <attr name="customTitleText" format="string"/> </declare-styleable>属性使用:
<com.project.viewtestdemo1.view.MyTextView android:layout_width="wrap_content" android:layout_height="wrap_content" app:customTitleText="自定义文字" />
(2)、color:颜色
属性定义:
属性使用
属性定义:
属性定义:
属性定义:
属性定义:
属性定义:
属性定义:
属性定义:
属性定义:
<declare-styleable name="名称"> <attr format="color" name="textColor" /> </declare-styleable>
属性使用
<TextView android:layout_width="42dip" android:layout_height="42dip" android:textColor="#00FF00" />(3)、integer:整型值
属性定义:
<declare-styleable name="AnimatedRotateDrawable"> <attr format="integer" name="frameDuration" /> <attr format="integer" name="framesCount" /> </declare-styleable>属性使用
<animated-rotate android:frameDuration="100" android:framesCount="12" />(4)、dimession:尺寸值
属性定义:
<declare-styleable name="名称"> <attr format="dimension" name="layout_width" /> </declare-styleable>属性使用
<Button android:layout_width="42dip" android:layout_height="42dip" />(5)、enum:枚举
属性定义:
<declare-styleable name="名称"> <attr name="orientation"> <enum name="horizontal" value="0" /> <enum name="vertical" value="1" /> </attr> </declare-styleable>属性使用
<LinearLayout android:orientation="vertical" > </LinearLayout>(6)、reference:参考某一资源ID
属性定义:
<declare-styleable name="名称"> <attr format="reference" name="background" /> </declare-styleable>属性使用
<ImageView android:layout_width="42dip" android:layout_height="42dip" android:background="@drawable/图片ID" />(7)、boolean布尔值
属性定义:
<declare-styleable name="名称"> <attr format="boolean" name="focusable" /> </declare-styleable>属性使用
<Button android:layout_width="42dip" android:layout_height="42dip" android:focusable="true" />(8)、float:浮点数
属性定义:
<declare-styleable name="AlphaAnimation"> <attr format="float" name="fromAlpha" /> <attr format="float" name="toAlpha" /> </declare-styleable>属性使用
<alpha android:fromAlpha="1.0" android:toAlpha="0.7" />(9)、fraction:百分数
属性定义:
<declare-styleable name="RotateDrawable"> <attr format="fraction" name="pivotX" /> <attr format="fraction" name="pivotY" /> </declare-styleable>属性使用
<rotate android:pivotX="200%" android:pivotY="300%" />(10)、flag:位或运算
属性定义:
<declare-styleable name="名称"> <attr name="windowSoftInputMode"> <flag name="stateUnspecified" value="0"/> <flag name="stateUnchanged" value="1"/> <flag name="stateHidden" value="2"/> <flag name="stateAlwaysHidden" value="3"/> <flag name="stateVisible" value="4"/> <flag name="stateAlwaysVisible" value="5"/> <flag name="adjustUnspecified" value="0x00"/> <flag name="adjustResize" value="0x10"/> <flag name="adjustPan" value="0x20"/> <flag name="adjustNothing" value="0x30"/> </attr></declare-styleable>
属性使用:
<activity
android:windowSoftInputMode="stateUnspecified | stateUnchanged | stateHidden" >
</activity>
要使用自定义view中的自定义属性必须在根布局上添加xmlns:名称="http://schemas.android.com/apk/res-auto"后面的res-auto可以换成res/自定义view的全路径名
2、在自定义view的构造函数中,获取自定义属性
基本已经实现了自定义View。但是此时如果我们把布局文件的宽和高写成wrap_content,会发现效果并不是我们的预期:
可以看到系统帮我们测量的宽高都是MATCH_PARNET,当我们设置了明确的宽高的时候,系统帮我们测量的宽高就是我们设置的宽高,当我们设置WRAP_CONTENT或MATCH_PARNET的时候,系统帮我们测量的都是MATCH_PARNET。
所以,当我们设置WRAP_CONTENT的时候,我们需要重写onMeasure()。
重写之前我们要了解MeasureSpec的specMode,一共三种类型:
1、EXACTLY:一般是设置了明确的值或者是MATCH_PARENT
2、AT_MOST:表示子布局限制在一个最大值内,一般为WARP_CONTENT
3、UNSPECIFIED:表示子布局想要多大就多大,很少使用
我们重写onMeasure方法:
然后修改布局文件:
完全复合我们的预期,现在我们可以对高度、宽度进行随便的设置了,基本可以满足我们的需求。
在构造中添加点击事件
要使用自定义view中的自定义属性必须在根布局上添加xmlns:名称="http://schemas.android.com/apk/res-auto"后面的res-auto可以换成res/自定义view的全路径名
2、在自定义view的构造函数中,获取自定义属性
public class MyTextView extends View { private String mText; private int mTextColor; private float mTextSize; private Paint mPaint; private Rect mRect; public MyTextView(Context context) { this(context, null); } public MyTextView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public MyTextView(Context context, AttributeSet attrs, int defStyleRes) { super(context, attrs, defStyleRes); //获取属性 TypedArray typedArray = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CustomTextView, defStyleRes, 0); int indexCount = typedArray.getIndexCount(); for (int i = 0; i < indexCount; i++) { int index = typedArray.getIndex(i); switch (index) { case R.styleable.CustomTextView_titleText: mText = typedArray.getString(index); break; case R.styleable.CustomTextView_titleTextColor: mTextColor = typedArray.getColor(index, Color.BLACK); break; case R.styleable.CustomTextView_titleTextSize: //默认设置16sp,TypeValue也可以把sp转成px mTextSize = typedArray.getDimensionPixelSize(index, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 16, getResources().getDisplayMetrics())); break; default: break; } } //一定要记得释放 typedArray.recycle(); /** * 获取绘制文本的宽和高 */ mPaint = new Paint(); mPaint.setTextSize(mTextSize); mRect = new Rect(); //计算文字所在矩形,可以得到宽高 mPaint.getTextBounds(mText, 0, mText.length(), mRect); }}3、重写onDraw()、onMeasure()调用父类的:
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); mPaint.setColor(Color.GREEN); canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), mPaint); mPaint.setColor(mTextColor); //参数1:要画的文字 2、从x轴开始绘制 3、y轴开始画的位置 canvas.drawText(mText, getWidth() / 2 - mRect.width() / 2, getHeight() / 2 + mRect.height() / 2, mPaint); }
基本已经实现了自定义View。但是此时如果我们把布局文件的宽和高写成wrap_content,会发现效果并不是我们的预期:
可以看到系统帮我们测量的宽高都是MATCH_PARNET,当我们设置了明确的宽高的时候,系统帮我们测量的宽高就是我们设置的宽高,当我们设置WRAP_CONTENT或MATCH_PARNET的时候,系统帮我们测量的都是MATCH_PARNET。
所以,当我们设置WRAP_CONTENT的时候,我们需要重写onMeasure()。
重写之前我们要了解MeasureSpec的specMode,一共三种类型:
1、EXACTLY:一般是设置了明确的值或者是MATCH_PARENT
2、AT_MOST:表示子布局限制在一个最大值内,一般为WARP_CONTENT
3、UNSPECIFIED:表示子布局想要多大就多大,很少使用
我们重写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; int height; if (widthMode == MeasureSpec.EXACTLY) {//有明确的值或者MATCH_PARENT width = widthSize; } else { mPaint.setColor(mTextColor); mPaint.getTextBounds(mText, 0, mText.length(), mRect); int textWidth = mRect.width();//获取文字高度 width = getPaddingLeft() + textWidth + getPaddingRight(); } if (heightMode == MeasureSpec.EXACTLY) { height = heightSize; } else { mPaint.setColor(mTextColor); mPaint.getTextBounds(mText, 0, mText.length(), mRect); int textHeight = mRect.height(); height = getPaddingTop() + textHeight + getPaddingBottom(); } setMeasuredDimension(width,height); }
然后修改布局文件:
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent"> <com.project.viewtestdemo1.view.MyTextView android:id="@+id/mtv" android:layout_width="wrap_content" android:layout_height="wrap_content" app:titleText="自定义文字" app:titleTextColor="#000" app:titleTextSize="20sp" android:padding="10dp" android:layout_centerInParent="true" /></RelativeLayout>运行效果:
完全复合我们的预期,现在我们可以对高度、宽度进行随便的设置了,基本可以满足我们的需求。
在构造中添加点击事件
this.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { mText = randomText(); postInvalidate();//更新view } });
private String randomText() { Random random = new Random(); Set<Integer> set = new HashSet<Integer>(); while (set.size() < 4) { int randomInt = random.nextInt(10); set.add(randomInt); } StringBuffer sb = new StringBuffer(); for (Integer i : set) { sb.append("" + i); } return sb.toString(); }
0 0
- Android View---自定义View
- Android View---自定义View
- Android 自定义View 之 自定义View属性
- 【自定义View系列】android自定义View概述
- Android自定义view自定义属性
- Android自定义控件 -- 自定义View
- android自定义view(自定义数字键盘)
- Android自定义View-自定义属性
- Android自定义View-自定义属性
- Android 自定义View
- Android 自定义 View
- android自定义View
- Android 中自定义 view
- android 自定义view组件
- Android 自定义 View
- android 自定义view
- Android:如何自定义View
- android 自定义View
- hihcoder 1117 战争年代
- 高通平台常见的一些错误(持续更新)
- 349. Intersection of Two Arrays
- omnet++ :Cannot run program Error launch simulation for "项目名"
- Git 基本用法上
- Android自定义view
- LeetCode:Find the Difference
- 让一台电脑只能上一个QQ的方法
- 计算机网络:数据链路层03
- JS的取经之路(四)
- Android studio导入Github的项目
- 【maven】mac下maven 配置(转)
- Mac OSX下开机启动守护进程,接受远程命令,从而启动、通信cocoa app
- 构建10G数据中心需要哪些光纤产品?