自定义VIew
2016-07-15 23:42
281 查看
自定义View实现圆形进度条
在开始自定义View前需要先了解一些背景知识通过Android官方API我们可以了解到Implementing a Custom View
To implement a custom view, you will usually begin by providing overrides for some of the standard methods that the framework calls on all views. You do not need to override all of these methods. In fact, you can start by just overridingonDraw(android.graphics.Canvas).
Category | Methods | Description |
---|---|---|
Creation | Constructors | There is a form of the constructor that are called when the view is created from code and a form that is called when the view is inflated from a layout file. The second form should parse and apply any attributes defined in the layout file. |
onFinishInflate() | Called after a view and all of its children has been inflated from XML. | |
Layout | onMeasure(int, int) | Called to determine the size requirements for this view and all of its children. |
onLayout(boolean, int, int, int, int) | Called when this view should assign a size and position to all of its children. | |
onSizeChanged(int, int, int, int) | Called when the size of this view has changed. | |
Drawing | onDraw(android.graphics.Canvas) | Called when the view should render its content. |
Event processing | onKeyDown(int, KeyEvent) | Called when a new hardware key event occurs. |
onKeyUp(int, KeyEvent) | Called when a hardware key up event occurs. | |
onTrackballEvent(MotionEvent) | Called when a trackball motion event occurs. | |
onTouchEvent(MotionEvent) | Called when a touch screen motion event occurs. | |
Focus | onFocusChanged(boolean, int, android.graphics.Rect) | Called when the view gains or loses focus. |
onWindowFocusChanged(boolean) | Called when the window containing the view gains or loses focus. | |
Attaching | onAttachedToWindow() | Called when the view is attached to a window. |
onDetachedFromWindow() | Called when the view is detached from its window. | |
onWindowVisibilityChanged(int) | Called when the visibility of the window containing the view has changed. |
下面开始做这样一个小的Demo。分为如下几个步骤:
1.自定义属性资源,在android中我们可以通过配置XML来给VIew设置相关的属性
2.新建MyView类继承VIew
3.将MyView添加到activity_main.xml文件
1.在res/value文件夹下新建属性文件attrs.xml
declare-styleable标签声明属性集。 attr声明属性 这里自定义View实现圆形进度条所以配置如下属性:
圆环的颜色:roundColor 进度的颜色:round 圆环的宽度(直径):roundWidth 中间显示字体的颜色:textColor 中间显示字体的大小:textSize 最大进度:max 是否显示圆环进度中心的字体:textIsDisplayable 圆环的风格(实心或空心):style
<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="MyView"> <attr name="roundColor" format="color"/> <attr name="roundProgressColor" format="color"/> <attr name="roundWidth" format="dimension"/> <attr name="textColor" format="color"/> <attr name="textSize" format="dimension"/> <attr name="max" format="integer"/> <attr name="textIsDisplayable" format="boolean"/> <attr name="style"> <enum name="STROKE" value="0"></enum> <enum name="FILL" value="1"></enum> </attr> </declare-styleable> </resources>
2.自定义View重写onDraw是关键参数Canvas代表的是画布在画布上我们可以通过Paint画自己想画的一些东西。但是在画之前需要先设置
画笔的一些属性。
自定义View实现圆环进度条是为了给其他父类控件使用因此需要对外暴露设置和取的这些属性的方法,但是其中的进度属性需要我们注意
因为在使用过程中进度一般是随时间而变化的会不断使用get、set方法来操作它,联系到在Android中主线程用来跟新界面,而不会有费时
操作来获取不断更新的进度每次进度更新后我们会通知主线程重新绘制。使用synchronized修饰progress属性的get、set方法保证在跟新
进度属性的时候不会有获取操作。
import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.RectF; import android.graphics.Typeface; import android.util.AttributeSet; import android.view.View; import com.example.administrator.defineviewbymyself.R; /** * Created by Administrator on 2016/7/15 0015. * * 对于View类 * extends Object * implements Drawable.Callback KeyEvent.Callback AccessibilityEventSource */ public class MyView extends View { /* * 字体内容 * */ String my_text; /* * 画笔对象的引用 * */ private Paint mPaint; /* * 圆环颜色 * */ private int roundColor; /* * 圆环进度的颜色 * */ private int roundProgressColor; /* * 圆环宽度 * */ private float roundWidth; /* * 中间进度百分比的字符串颜色的颜色 * */ private int textColor; /* * 中间进度百分比的字符串颜色的大小 * */ private float textSize; /* * 最大进度 * */ private Integer max; /* * 是否显示中间进度 * */ private boolean textIsDisplayable; /* * 进度风格,实心或空心 * */ private int style; /* * 当前进度 * */ //这里把进度设置为50只是为了示例能够看到效果 private int progress = 50; public static final int STROKE = 0; public static final int FILL = 1; /* * 该构造方法在Java代码中创建MyView对象调用 * @param Context来字 * */ public MyView(Context context) { this(context,null); } /* *在布局文件中设置MyView系统会调用该方法 * AttributeSet attrs与属性相关的一些东西 * 在资源文件中配置 * */ public MyView(Context context, AttributeSet attrs) { this(context, attrs,0); } /* * int defStyleAttr MyView的默认样式 * */ public MyView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); mPaint = new Paint(); TypedArray mTypedArray = context.obtainStyledAttributes(attrs,R.styleable.MyView); //获取自定义属性或默认值 roundColor = mTypedArray.getColor(R.styleable.MyView_roundColor, Color.RED); roundProgressColor = mTypedArray.getColor(R.styleable.MyView_roundProgressColor,Color.GREEN); textColor = mTypedArray.getColor(R.styleable.MyView_textColor,Color.GREEN); textSize = mTypedArray.getDimension(R.styleable.MyView_textSize,15); roundWidth = mTypedArray.getDimension(R.styleable.MyView_roundWidth,5); max = mTypedArray.getInteger(R.styleable.MyView_max,100); textIsDisplayable = mTypedArray.getBoolean(R.styleable.MyView_textIsDisplayable,true); style = mTypedArray.getInt(R.styleable.MyView_style,0); mTypedArray.recycle(); } /* 重写onDraw是自定义View的关键 */ @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); /* * 画最外层的大圆环 * */ int centre = getWidth()/2;//圆心坐标 int radius = (int) (centre - roundWidth/2);//圆环半径 mPaint.setColor(roundColor);//设置圆环的颜色 mPaint.setStyle(Paint.Style.STROKE);//设置空心 mPaint.setStrokeWidth(roundWidth);//设置圆环的宽度 mPaint.setAntiAlias(true);//消除锯齿 canvas.drawCircle(centre,centre,radius,mPaint);//画出圆环 /* * 画进度百分比 * */ mPaint.setStrokeWidth(0);//清楚上面的设置空心线宽 mPaint.setColor(textColor);//设置字体颜色 mPaint.setTextSize(textSize);//设置字体大小 mPaint.setTypeface(Typeface.DEFAULT_BOLD);//设置字体 int percent = (int) ((float)progress/(float)max*100);//中间的进度百分比,先转换成float在进行除法运算,不然都为0 float textWidth = mPaint.measureText(percent+"%"); if(textIsDisplayable && percent != 0 && style == STROKE){ canvas.drawText(percent + "%", centre - textWidth / 2, centre + textSize/2, mPaint); //画出进度百分比 } /* * 画圆弧,画圆环的进度 * */ //设置进度是实心还是空心 mPaint.setStrokeWidth(roundWidth);//设置圆环的宽度 mPaint.setColor(roundProgressColor);//设置进度的颜色 RectF oval = new RectF(centre-radius,centre-radius,centre+radius,centre+radius);//用于定义的圆弧的形状和大小的界限 /* * STROKE:代表空心 * FILL:代表实心 * */ switch (style){ case STROKE:{ mPaint.setStyle(Paint.Style.STROKE); canvas.drawArc(oval,0,360*progress/max,false,mPaint);; break; } case FILL:{ mPaint.setStyle(Paint.Style.FILL_AND_STROKE); if(progress !=0) canvas.drawArc(oval, 0, 360 * progress / max, true, mPaint); //根据进度画圆弧 break; } } } public synchronized int getMax(){ return max; } /* * 设置进度的最大值 * @param max * */ public synchronized void setMax(){ if(max < 0){ throw new IllegalArgumentException("max not less than 0"); } this.max = max; } /* * 获取进度,需要同步 * @return * */ public synchronized int getProgress(){ return progress; } /** * 设置进度,此为线程安全控件,由于考虑多线的问题,需要同步 * 刷新界面调用postInvalidate()能在非UI线程刷新 * @param progress */ public synchronized void setProgress(int progress) { if(progress < 0){ throw new IllegalArgumentException("progress not less than 0"); } if(progress > max){ progress = max; } if(progress <= max){ this.progress = progress; postInvalidate(); } } public String getMy_text() { return my_text; } public void setMy_text(String my_text) { this.my_text = my_text; } public int getRoundColor() { return roundColor; } public void setRoundColor(int roundColor) { this.roundColor = roundColor; } public int getRoundProgressColor() { return roundProgressColor; } public void setRoundProgressColor(int roundProgressColor) { this.roundProgressColor = roundProgressColor; } public float getRoundWidth() { return roundWidth; } public void setRoundWidth(float roundWidth) { this.roundWidth = roundWidth; } public int getTextColor() { return textColor; } public void setTextColor(int textColor) { this.textColor = textColor; } public float getTextSize() { return textSize; } public void setTextSize(float textSize) { this.textSize = textSize; } public boolean isTextIsDisplayable() { return textIsDisplayable; } public void setTextIsDisplayable(boolean textIsDisplayable) { this.textIsDisplayable = textIsDisplayable; } public int getStyle() { return style; } public void setStyle(int style) { this.style = style; } public void init(){ mPaint = new Paint(); } }
3.配置activity_main.xml
其中xmls:myview="com\example\administrator\defineviewbymyself\my_view"是定义MyView类的地方。
<?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:myview="com\example\administrator\defineviewbymyself\my_view" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="com.example.administrator.defineviewbymyself.MainActivity"> <com.example.administrator.defineviewbymyself.my_view.MyView android:layout_width="match_parent" android:layout_height="match_parent" /> </RelativeLayout>4.MainActivity相关代码就补贴上来了。只需要把activity_main.xml关联进去即可。
最后实现效果
想要实现其他效果只需要在onDraw()方法设置即可
相关文章推荐
- struts2拦截器详解
- NOIP2013 D2T1 积木大赛
- 在亚马逊的EC2,ubuntu上面搭建php+mysql+apach+phpmyadmin环境
- 四层和七层负载均衡的区别
- C语言指针定义变量方式
- centos下hadoop-2.6.0完全分布式搭建
- React.js 之筛选篇
- scala基础3-文件操作
- CDOJ 1256 二维前缀和处理
- NOIP2011 D1T1 铺地毯
- 7.15
- Unity3D 2D入门——第3天:C# ,我继续.......
- NOIP2011 D1T1 铺地毯
- Nginx - Windows下Nginx初入门
- HDOJ 1009 FAT MOUSE TRADE
- 二项分布算法(递归)
- 使用和学习 ES2015
- 小学生四则运算出题程序 无操作界面java版 简单的运用java中一些基本操作
- Class.forName的作用以及为什么要用它
- Cocos2dx-3.x触摸事件之实现人机交互(二)