android UI自定义组件
来源:互联网 发布:收看电视直播的软件 编辑:程序博客网 时间:2024/05/20 16:40
转载: http://blog.csdn.net/yjp19871013/article/details/54849308
本文主要讲讲如何派生View类,实现Android自定义控件。通过派生View实现自定义控件首先要清楚两个步骤:测量与绘制。
自定义控件首先要为Android框架提供其内容的测量值,这个阶段在onMeasure方法中进行,我们可以重写该方法,提供测量值。测量阶段发生在绘制之前,在测量期间,视图还没有确切的大小,只有侧量尺寸。如果在分配大小后还需要做处理,那就要重写onSizeChanged方法。
测量阶段onMeasure方法会传入两个参数,分别是宽和高对应的MeasureSpec的整型值,它有三个值:
AT_MOST:当我们的布局参数使用match_parent或者其他给出大小上限的参数值时,会传入该模式,我们的onMeasure应当返回对应的上限值。
EXACTLY:当布局参数是固定值时,会传入该模式,我们的onMeasure应当返回对应的宽和高的确切值。
UNSPECIFIED:当视图无约束时,会传入该模式,onMeasure应当返回宽和高都为0.
完成测量阶段后,会进入绘制阶段,这个阶段需要重写onDraw方法,传入的参数是Android框架按照测量阶段的数值创建的Canvas实例,我们基于该实例进行绘制即可。
下面是一个例子,实现了一个倾斜45度的TextView,它可以按照文本大小调整自己的宽高,然后和父视图边框接合,效果如图
下面看看代码,首先是我们的视图类
- package com.yjp.rotationtextview;
- import android.content.Context;
- import android.graphics.Canvas;
- import android.graphics.Paint;
- import android.graphics.Path;
- import android.graphics.RectF;
- import android.graphics.drawable.ColorDrawable;
- import android.graphics.drawable.Drawable;
- import android.util.AttributeSet;
- import android.widget.TextView;
- public class RotationTextView extends TextView {
- private Drawable mBackground;
- public RotationTextView(Context context) {
- //调用自己的构造函数
- this(context, null);
- }
- public RotationTextView(Context context, AttributeSet attrs) {
- //调用自己的构造函数
- this(context, attrs, 0);
- }
- public RotationTextView(Context context, AttributeSet attrs, int defStyle) {
- //调用超类TextView的构造函数
- super(context, attrs, defStyle);
- }
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- //获取文本的宽度,以计算倾斜45度后的长度,注意计算宽度和高度的代码不同
- int textWidth = (int) getPaint().measureText(getText().toString(), 0, getText().length());
- int min = (int) (textWidth / Math.cos(Math.PI / 4));
- //调用resolveSizeAndState()快捷方法计算尺寸
- int w = resolveSizeAndState(min, widthMeasureSpec, 0);
- int h = resolveSizeAndState(min, heightMeasureSpec, 0);
- int result = Math.max(w, h);
- //必须调用
- setMeasuredDimension(result, result);
- }
- @SuppressWarnings(“deprecation”)
- @Override
- protected void onDraw(Canvas canvas) {
- //设置绘制背景使用的Paint
- Paint backgroundPaint = new Paint();
- backgroundPaint.setAntiAlias(true);
- backgroundPaint.setStyle(Paint.Style.FILL);
- if (mBackground != null) {
- backgroundPaint.setColor(((ColorDrawable)mBackground).getColor());
- } else {
- backgroundPaint.setColor(getContext().getResources().getColor(android.R.color.white));
- }
- //获取字符串高度,注意计算宽度和高度的代码不同
- Paint.FontMetrics fm = getPaint().getFontMetrics();
- double textHeight = Math.ceil(fm.descent - fm.top);
- //绘制梯形外边框,并填充颜色
- Path backgroundPath = new Path();
- backgroundPath.moveTo(0, getHeight() - (int) textHeight - 20);
- backgroundPath.lineTo(0, getHeight());
- backgroundPath.lineTo(getWidth(), 0);
- backgroundPath.lineTo(getWidth() - (int) textHeight - 20, 0);
- backgroundPath.close();
- canvas.drawPath(backgroundPath, backgroundPaint);
- //绘制文本
- RectF backgroundRectF = new RectF();
- backgroundPath.computeBounds(backgroundRectF, false);
- int textWidth = (int) getPaint().measureText(getText().toString(), 0, getText().length());
- double delta = textWidth / 2 * Math.cos(Math.PI / 4);
- Path textPath = new Path();
- textPath.moveTo((float)(backgroundRectF.centerX() - delta - 5),
- (float)(backgroundRectF.centerY() + delta - 5));
- textPath.lineTo((float)(backgroundRectF.centerX() + delta - 5),
- (float)(backgroundRectF.centerY() - delta - 5));
- canvas.drawTextOnPath(getText().toString(), textPath, 0, 0, getPaint());
- }
- //需要重载一系列background相关的函数,否则TextView默认用该background填充整个正方形视图
- //所有函数最终调用的都是setBackgroundDrawable()
- @SuppressWarnings(“deprecation”)
- @Override
- public void setBackgroundResource(int resid) {
- Drawable d = null;
- if (resid != 0) {
- d = getContext().getResources().getDrawable(resid);
- }
- this.setBackground(d);
- }
- @Override
- public void setBackgroundColor(int color) {
- if (mBackground instanceof ColorDrawable) {
- ((ColorDrawable) mBackground.mutate()).setColor(color);
- } else {
- this.setBackground(new ColorDrawable(color));
- }
- }
- @Override
- public void setBackground(Drawable background) {
- this.setBackgroundDrawable(background);
- }
- @SuppressWarnings(“deprecation”)
- @Override
- public void setBackgroundDrawable(Drawable background) {
- mBackground = background;
- }
- }
package com.yjp.rotationtextview;import android.content.Context;import android.graphics.Canvas;import android.graphics.Paint;import android.graphics.Path;import android.graphics.RectF;import android.graphics.drawable.ColorDrawable;import android.graphics.drawable.Drawable;import android.util.AttributeSet;import android.widget.TextView;public class RotationTextView extends TextView { private Drawable mBackground; public RotationTextView(Context context) { //调用自己的构造函数 this(context, null); } public RotationTextView(Context context, AttributeSet attrs) { //调用自己的构造函数 this(context, attrs, 0); } public RotationTextView(Context context, AttributeSet attrs, int defStyle) { //调用超类TextView的构造函数 super(context, attrs, defStyle); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { //获取文本的宽度,以计算倾斜45度后的长度,注意计算宽度和高度的代码不同 int textWidth = (int) getPaint().measureText(getText().toString(), 0, getText().length()); int min = (int) (textWidth / Math.cos(Math.PI / 4)); //调用resolveSizeAndState()快捷方法计算尺寸 int w = resolveSizeAndState(min, widthMeasureSpec, 0); int h = resolveSizeAndState(min, heightMeasureSpec, 0); int result = Math.max(w, h); //必须调用 setMeasuredDimension(result, result); } @SuppressWarnings("deprecation") @Override protected void onDraw(Canvas canvas) { //设置绘制背景使用的Paint Paint backgroundPaint = new Paint(); backgroundPaint.setAntiAlias(true); backgroundPaint.setStyle(Paint.Style.FILL); if (mBackground != null) { backgroundPaint.setColor(((ColorDrawable)mBackground).getColor()); } else { backgroundPaint.setColor(getContext().getResources().getColor(android.R.color.white)); } //获取字符串高度,注意计算宽度和高度的代码不同 Paint.FontMetrics fm = getPaint().getFontMetrics(); double textHeight = Math.ceil(fm.descent - fm.top); //绘制梯形外边框,并填充颜色 Path backgroundPath = new Path(); backgroundPath.moveTo(0, getHeight() - (int) textHeight - 20); backgroundPath.lineTo(0, getHeight()); backgroundPath.lineTo(getWidth(), 0); backgroundPath.lineTo(getWidth() - (int) textHeight - 20, 0); backgroundPath.close(); canvas.drawPath(backgroundPath, backgroundPaint); //绘制文本 RectF backgroundRectF = new RectF(); backgroundPath.computeBounds(backgroundRectF, false); int textWidth = (int) getPaint().measureText(getText().toString(), 0, getText().length()); double delta = textWidth / 2 * Math.cos(Math.PI / 4); Path textPath = new Path(); textPath.moveTo((float)(backgroundRectF.centerX() - delta - 5), (float)(backgroundRectF.centerY() + delta - 5)); textPath.lineTo((float)(backgroundRectF.centerX() + delta - 5), (float)(backgroundRectF.centerY() - delta - 5)); canvas.drawTextOnPath(getText().toString(), textPath, 0, 0, getPaint()); } //需要重载一系列background相关的函数,否则TextView默认用该background填充整个正方形视图 //所有函数最终调用的都是setBackgroundDrawable() @SuppressWarnings("deprecation") @Override public void setBackgroundResource(int resid) { Drawable d = null; if (resid != 0) { d = getContext().getResources().getDrawable(resid); } this.setBackground(d); } @Override public void setBackgroundColor(int color) { if (mBackground instanceof ColorDrawable) { ((ColorDrawable) mBackground.mutate()).setColor(color); } else { this.setBackground(new ColorDrawable(color)); } } @Override public void setBackground(Drawable background) { this.setBackgroundDrawable(background); } @SuppressWarnings("deprecation") @Override public void setBackgroundDrawable(Drawable background) { mBackground = background; }}重点在onMeasure和onDraw方法上,另外为了能够支持视图设置background属性,我们重写了setBackgroundxxx的一系列方法。下面是布局
- <?xml version=“1.0” encoding=“utf-8”?>
- <FrameLayout xmlns:android=“http://schemas.android.com/apk/res/android”
- xmlns:tools=“http://schemas.android.com/tools”
- android:layout_width=“match_parent”
- android:layout_height=“match_parent”
- android:background=“@android:color/holo_green_light”
- tools:context=“com.yjp.rotationtextview.MainActivity”>
- <com.yjp.rotationtextview.RotationTextView
- android:layout_width=“wrap_content”
- android:layout_height=“wrap_content”
- android:background=“@android:color/holo_orange_light”
- android:text=“测试文本1”
- android:textSize=“20sp”
- android:textColor=“@android:color/holo_red_dark”/>
- <com.yjp.rotationtextview.RotationTextView
- android:layout_width=“wrap_content”
- android:layout_height=“wrap_content”
- android:background=“@android:color/holo_blue_bright”
- android:text=“测试文本2”
- android:textSize=“40sp”
- android:textColor=“@android:color/holo_red_dark”/>
- <com.yjp.rotationtextview.RotationTextView
- android:layout_width=“wrap_content”
- android:layout_height=“wrap_content”
- android:background=“@android:color/holo_purple”
- android:text=“测试文本3”
- android:textSize=“60sp”
- android:textColor=“@android:color/holo_red_dark”/>
- </FrameLayout>
<?xml version="1.0" encoding="utf-8"?><FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/holo_green_light" tools:context="com.yjp.rotationtextview.MainActivity"> <com.yjp.rotationtextview.RotationTextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@android:color/holo_orange_light" android:text="测试文本1" android:textSize="20sp" android:textColor="@android:color/holo_red_dark"/> <com.yjp.rotationtextview.RotationTextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@android:color/holo_blue_bright" android:text="测试文本2" android:textSize="40sp" android:textColor="@android:color/holo_red_dark"/> <com.yjp.rotationtextview.RotationTextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@android:color/holo_purple" android:text="测试文本3" android:textSize="60sp" android:textColor="@android:color/holo_red_dark"/></FrameLayout>
谢谢观看!
阅读全文
0 0
- android自定义UI组件
- android UI自定义组件
- Android开发自定义UI组件
- Android学习笔记之自定义UI组件
- Android应用开发学习笔记之开发自定义UI组件
- Android UI组件----自定义ListView实现动态刷新
- Android开发之自定义UI组件和属性
- React-Native系列Android自定义原生UI组件
- android--UI组件总结
- android--UI组件总结
- android UI组件----菜单
- Android的UI组件
- android UI组件
- android基础UI组件
- Android UI组件
- Android的UI组件 .
- Android UI组件
- Android UI组件
- linux操作系统下部署Javaweb项目教程
- Nginx负载均衡与高可用的实现
- 判断网络是否连接
- javascript中获取dom元素高度和宽度的方法如下:
- cf 442 div2 D bfs最短路
- android UI自定义组件
- 济南模拟赛day3t1
- C++之初识类
- 了解Maven(一)
- turtlebot机器人模拟平台
- Django REST FrameWork中文教程6: ViewSets&Routers
- 栈的应用_简单表达式求值
- JS之 输入框限制输入数字且最大精确到小数点后两位
- NOIP 模拟题 奇怪的字符串