尊重原创,转载请注明出处: http://blog.csdn.net/qq137722697
自定义view是Android工程师进阶不可避免要接触的,我的学习心得就是动手写,之后将推出系列自定view的文章,敬请期待,本篇将带来一个非常简单的自定义控件——>太极图。
先来看看最终的效果:
大部分自定义view无外乎包含三个方面的内容:
先来分析这个图应该怎么画,来看一个动态图:
1、先画一个黑色的圆;
2、画左边的白色半圆;
3、画上边白色的中圆;
4、画下边黑色的中圆;
5、画上边黑色的小圆;
6、画下面白色的小圆。
另外就是关于屏幕的坐标系,不是数学中的那种哦看下图你就明白了,Y轴的方向是向下的:
下面来看看代码如何实现:
第一步,创建一个继承至View的类,重写三个构造方法
public class TJView extends View {
public TJView(Context context) {
this(context, null);
}
public TJView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public TJView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
}
第二步、来看看画太极需要属性
//画笔工具
private Paint mPaint;
//圆心坐标--屏幕的宽高来设置-->目的是默认居中显示
private float currentX = 0;
private float currentY = 0;
//大圆半径
private float radiusBig = 200;
//中圆半径
private float radiusCenter = radiusBig / 2;
//小圆半径
private float radiusSmall = radiusCenter / 3;
//边距(主要作用是画黑色大圆的时候,为了达到有边框的效果,半径需要比原来的大一点)
private int padding = 8;
第三步、初始化画笔(第三个构造方法中)
public TJView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mPaint = new Paint();
mPaint.setAntiAlias(true);//去掉锯齿
}
第四步、拿到屏幕中心点的坐标
这里需要重写onMeasure方法来拿到实际测量的值
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
currentX = MeasureSpec.getSize(widthMeasureSpec) / 2;//通过MeasureSpec拿到X轴
currentY = MeasureSpec.getSize(heightMeasureSpec) / 2;//通过MeasureSpec拿到Y轴
setMeasuredDimension(widthMeasureSpec, heightMeasureSpec);//测绘
}
准备工作就绪,开始画
第五步、画一个黑色的大圆(此时圆点坐标、半径已经准备就绪了)
同样的需要重写onDraw方法—具体的业务抽成方法便于理解
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
drawBg(canvas);//画黑色大圆
drawLeftHalfCirle(canvas);//画左边白色半圆
drawTBCirle(canvas);//画上下的四个圆
}
/**
* 画黑色的背景底板
*
* @param canvas
*/
private void drawBg(Canvas canvas) {
mPaint.setColor(Color.BLACK);//设置背景颜色为黑色
canvas.drawCircle(currentX, currentY, radiusBig + padding, mPaint);//这里加padding才有边框效果
}
/**
* 画左边半圆
*
* @param canvas
*/
private void drawLeftHalfCirle(Canvas canvas) {
mPaint.setColor(Color.WHITE);
canvas.drawArc(new RectF(currentX - radiusBig, currentY - radiusBig, currentX + radiusBig, currentY + radiusBig), 90, 180, true, mPaint);//90度开始画 画180度
}
/**
* 画上下两个圆--中圆和小圆
*
* @param canvas
*/
private void drawTBCirle(Canvas canvas) {
//画上面的白中圆
mPaint.setColor(Color.WHITE);
canvas.drawCircle(currentX, currentY - radiusBig / 2, radiusCenter, mPaint);
//画上面的黑小圆
mPaint.setColor(Color.BLACK);
canvas.drawCircle(currentX, currentY - radiusBig / 2, radiusSmall, mPaint);
//画下面的黑中圆
mPaint.setColor(Color.BLACK);
canvas.drawCircle(currentX, currentY + radiusBig / 2, radiusCenter, mPaint);
//画下面的白小圆
mPaint.setColor(Color.WHITE);
canvas.drawCircle(currentX, currentY + radiusBig / 2, radiusSmall, mPaint);
}
这样一个标准的太极图就画出来了,效果图就是一开始那个;
下面加点交互效果,——>用户拖动的时候太极图会随手指的移动而移动;
这里需要重写onTouchEvent方法
上代码:
@Override
public boolean onTouchEvent(MotionEvent event) {
currentX = event.getX();//获取当前手指所在x轴
currentY = event.getY();//获取当前手指所在y轴
invalidate();//立刻重绘
return true;//返回true表示不通知父控件处理,自己处理
}
关于动画,下面就来加点缩放动画吧,同样先看效果:
/**
* 设置缩放动画
*/
private void setAnimation() {
ScaleAnimation scaleAnimation2 = new ScaleAnimation(0.7f, 1.0f, 0.7f, 1.0f, ScaleAnimation.RELATIVE_TO_PARENT, 0.5f, ScaleAnimation.RELATIVE_TO_PARENT, 0.5f);
scaleAnimation2.setDuration(500);// 设置持续时间
scaleAnimation2.setRepeatCount(99999);// 设置重复次数
scaleAnimation2.setFillAfter(true);// 保持动画结束时的状态
startAnimation(scaleAnimation2);
}
在第三个构造方法中调用:
public TJView(Context context, AttributeSet attrs, int defStyleAttr) {
//省略其余代码
setAnimation();
}
最后贴出完整的代码:
调用处:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_tj"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.hdl.myhttputilssimple.TJView
android:layout_width="match_parent"
android:layout_height="match_parent" />
RelativeLayout>
完整的TJView代码:
/**
* 太极图
* Created by HDL on 2016/12/27.
*/
public class TJView extends View {
private static final String TAG = "TJView";
private int padding = 8;
//画笔工具
private Paint mPaint;
//圆心坐标
private float currentX = 0;
private float currentY = 0;
//大圆半径
private float radiusBig = 200;
//中圆半径
private float radiusCenter = radiusBig / 2;
//小圆半径
private float radiusSmall = radiusCenter / 3;
public TJView(Context context) {
this(context, null);
}
public TJView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public TJView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mPaint = new Paint();
mPaint.setAntiAlias(true);
setAnimation();
}
/**
* 设置缩放动画
*/
private void setAnimation() {
ScaleAnimation scaleAnimation2 = new ScaleAnimation(0.7f, 1.0f, 0.7f, 1.0f, ScaleAnimation.RELATIVE_TO_PARENT, 0.5f, ScaleAnimation.RELATIVE_TO_PARENT, 0.5f);
scaleAnimation2.setDuration(500);// 设置持续时间
scaleAnimation2.setRepeatCount(99999);// 设置重复次数
scaleAnimation2.setFillAfter(true);// 保持动画结束时的状态
startAnimation(scaleAnimation2);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
drawBg(canvas);
drawLeftHalfCirle(canvas);
drawTBCirle(canvas);
}
/**
* 画上下两个圆--中圆和小圆
*
* @param canvas
*/
private void drawTBCirle(Canvas canvas) {
//画上面的白中圆
mPaint.setColor(Color.WHITE);
canvas.drawCircle(currentX, currentY - radiusBig / 2, radiusCenter, mPaint);
//画上面的黑小圆
mPaint.setColor(Color.BLACK);
canvas.drawCircle(currentX, currentY - radiusBig / 2, radiusSmall, mPaint);
//画下面的黑中圆
mPaint.setColor(Color.BLACK);
canvas.drawCircle(currentX, currentY + radiusBig / 2, radiusCenter, mPaint);
//画下面的白小圆
mPaint.setColor(Color.WHITE);
canvas.drawCircle(currentX, currentY + radiusBig / 2, radiusSmall, mPaint);
}
/**
* 画左边半圆
*
* @param canvas
*/
private void drawLeftHalfCirle(Canvas canvas) {
mPaint.setColor(Color.WHITE);
canvas.drawArc(new RectF(currentX - radiusBig, currentY - radiusBig, currentX + radiusBig, currentY + radiusBig), 90, 180, true, mPaint);//90度开始画180度
}
/**
* 画黑色的背景底板
*
* @param canvas
*/
private void drawBg(Canvas canvas) {
mPaint.setColor(Color.BLACK);
canvas.drawCircle(currentX, currentY, radiusBig + padding, mPaint);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
currentX = MeasureSpec.getSize(widthMeasureSpec) / 2;
currentY = MeasureSpec.getSize(heightMeasureSpec) / 2;
setMeasuredDimension(widthMeasureSpec, heightMeasureSpec);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
currentX = event.getX();
currentY = event.getY();
invalidate();
return true;
}
}
尊重原创,转载请注明出处: http://blog.csdn.net/qq137722697