自定义View,通过手势动态变化
实现效果:自定义一个View,通过手势监听事件重绘视图。
1.效果图
点击屏幕前和点击屏幕后,视图的变化。
2.制作过程:
程序文件。
需要a:属性文件。自定义属性。
public RoundView(Context context, AttributeSet attributeSet){
this(context,attributeSet,0);
}
//如果可以传入NULL值,则标记为@Nullable,如果不可以,则标注为@Nonnull
public RoundView(Context context, @Nullable AttributeSet attributeSet,int defStyleAttr){
this(context,attributeSet,defStyleAttr,0);
}
public RoundView(Context context, @Nullable AttributeSet attributeSet,int defStyleAttr,int defStyleRes){
super(context,attributeSet,defStyleAttr,defStyleRes);
//获取属性值,默认0 ?
TypedArray typedArray = context.obtainStyledAttributes(attributeSet,R.styleable.RoundView);
mRingRadius = typedArray.getDimension(R.styleable.RoundView_radius,0);
mRingWidth = typedArray.getDimension(R.styleable.RoundView_ring_width,0);
mRingColor = typedArray.getColor(R.styleable.RoundView_ring_color, getResources().getColor(R.color.ring_background));
mProgressRadius = typedArray.getDimension(R.styleable.RoundView_progress_ring_radius,0);
mProgressWidth = typedArray.getDimension(R.styleable.RoundView_progress_ring_width,0);
mProgressRingColor = typedArray.getColor(R.styleable.RoundView_progress_ring_color,getResources().getColor(R.color.colorAccent));
typedArray.recycle();
/**
* 随着Android SDK升级前某些接口能有更好、更安全接口来代替Android开发团队会把过时接口标识成deprecated, 开发文档提示使用新代替接口用GestureDetector构造函数4.1版本已经过时使用推荐:
mGestureDetector = new GestureDetector(this, this);
// 注意前this代表Context,this代表OnGestureListener
// Activity继承自Context, 而activity应该实现了(implements)OnGestureListener接口
*/
mGestureDetector = new GestureDetector(context,this);
init();
}
最后一个构造函数中有怎么使用自定义属性的方法。
C:重写Ondraw()函数。
@Override
public void onDraw(Canvas canvas){
x0 = getWidth()/2;
y0 = getHeight()/2;
mRingRadius = mRingRadius == 0 ? Math.min(getHeight()/2, getWidth()/2):mRingRadius;//没有给出属性值时,设置一个值
mRingWidth = mRingWidth == 0 ? mRingRadius/5 : mRingWidth;
//mRingRadius = mRingRadius - mRingWidth/2;//圆环真正的半径
mRingPaint.setStrokeWidth(mRingWidth);
canvas.drawCircle(x0,y0,mRingRadius,mRingPaint);
mProgressWidth = mProgressWidth == 0 ? mRingWidth/2 : mProgressWidth;
mProgressRingPaint.setStrokeWidth(mProgressWidth);
canvas.drawArc(new RectF(x0 - mRingRadius,y0 - mRingRadius,x0 + mRingRadius,y0 + mRingRadius),
startAngle,sweepAngle,false,mProgressRingPaint);
}
设置属性的值,画两个圆圈。
效果如图1所示。
d.重写手势监听接口的7个函数。
在这些函数中重写设置属性值,然后重新绘图即可。
@Override
public boolean onTouchEvent(MotionEvent e){
//把onTouchEvent托管给GestureDetector
return mGestureDetector.onTouchEvent(e);
}
@Override
public boolean onDown(MotionEvent e) {
//单击事件
sweepAngle = sweepAngle + 2;//每次单击增加5度
if(sweepAngle >= 360){
sweepAngle = 0;
}
invalidate();
return false;
}
@Override
public void onShowPress(MotionEvent e) {// 在Touch down之后一定时间(115ms)触发
}
@Override
public boolean onSingleTapUp(MotionEvent e) {// 用户(轻触触摸屏后)松开,由一个1个MotionEvent ACTION_UP触发
return false;
}
@Override
public void onLongPress(MotionEvent e) {
//sweepAngle = sweepAngle + 20;//每次单击增加18度
//invalidate();
// 长按后触发(Touch down之后一定时间(500ms))
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float x1, float x2){
//没有效果
double st1 = Math.atan((e1.getY() - y0)/(e1.getX() - x0));
double st2 = Math.atan((e2.getY() - y0)/(e2.getX() - x0));
sweepAngle = sweepAngle + (float)st2 - (float)st1;
invalidate();
return false;
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
return false;
}
invalidate():在主线程中重新调用onDraw()函数。
e:activity使用。
<!--设置自定义属性值APP:-->
<com.example.chengwenbo.mycustomview.RoundView
android:id="@+id/my_roundview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:radius="120dp"
app:ring_width="20dp"
app:progress_ring_width="10dp"/>
在布局文件可以设置属性值,也可以在代码中设置。
3.总结。
View子类中重新绘图,用invalidate()。
实现动态View的方法有很多种,这种是通过user的手势设置数据,重新绘制。还可以通过动画效果等实现。
完整的自定义view源代码。
package com.example.chengwenbo.mycustomview;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
public class RoundView extends View implements GestureDetector.OnGestureListener{
private GestureDetector mGestureDetector;
private float mRingRadius = 0;
private float mRingWidth = 0;
private int mRingColor = 0;
private float mProgressRadius = 0;
private float mProgressWidth = 0;
private int mProgressRingColor = 0;
private Paint mRingPaint;
private Paint mProgressRingPaint;
float x0 = 0;//圆圆心
float y0 = 0;
float startAngle = -90;//圆环开始角度
float sweepAngle = 90;
public RoundView(Context context){
this(context,null);
}
public RoundView(Context context, AttributeSet attributeSet){
this(context,attributeSet,0);
}
//如果可以传入NULL值,则标记为@Nullable,如果不可以,则标注为@Nonnull
public RoundView(Context context, @Nullable AttributeSet attributeSet,int defStyleAttr){
this(context,attributeSet,defStyleAttr,0);
}
public RoundView(Context context, @Nullable AttributeSet attributeSet,int defStyleAttr,int defStyleRes){
super(context,attributeSet,defStyleAttr,defStyleRes);
//获取属性值,默认0 ?
TypedArray typedArray = context.obtainStyledAttributes(attributeSet,R.styleable.RoundView);
mRingRadius = typedArray.getDimension(R.styleable.RoundView_radius,0);
mRingWidth = typedArray.getDimension(R.styleable.RoundView_ring_width,0);
mRingColor = typedArray.getColor(R.styleable.RoundView_ring_color, getResources().getColor(R.color.ring_background));
mProgressRadius = typedArray.getDimension(R.styleable.RoundView_progress_ring_radius,0);
mProgressWidth = typedArray.getDimension(R.styleable.RoundView_progress_ring_width,0);
mProgressRingColor = typedArray.getColor(R.styleable.RoundView_progress_ring_color,getResources().getColor(R.color.colorAccent));
typedArray.recycle();
/**
* 随着Android SDK升级前某些接口能有更好、更安全接口来代替Android开发团队会把过时接口标识成deprecated, 开发文档提示使用新代替接口用GestureDetector构造函数4.1版本已经过时使用推荐:
mGestureDetector = new GestureDetector(this, this);
// 注意前this代表Context,this代表OnGestureListener
// Activity继承自Context, 而activity应该实现了(implements)OnGestureListener接口
*/
mGestureDetector = new GestureDetector(context,this);
init();
}
@Override
public boolean onTouchEvent(MotionEvent e){
//把onTouchEvent托管给GestureDetector
return mGestureDetector.onTouchEvent(e);
}
@Override
public boolean onDown(MotionEvent e) {
//单击事件
sweepAngle = sweepAngle + 2;//每次单击增加5度
if(sweepAngle >= 360){
sweepAngle = 0;
}
invalidate();
return false;
}
@Override
public void onShowPress(MotionEvent e) {// 在Touch down之后一定时间(115ms)触发
}
@Override
public boolean onSingleTapUp(MotionEvent e) {// 用户(轻触触摸屏后)松开,由一个1个MotionEvent ACTION_UP触发
return false;
}
@Override
public void onLongPress(MotionEvent e) {
//sweepAngle = sweepAngle + 20;//每次单击增加18度
//invalidate();
// 长按后触发(Touch down之后一定时间(500ms))
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float x1, float x2){
//没有效果
double st1 = Math.atan((e1.getY() - y0)/(e1.getX() - x0));
double st2 = Math.atan((e2.getY() - y0)/(e2.getX() - x0));
sweepAngle = sweepAngle + (float)st2 - (float)st1;
invalidate();
return false;
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
return false;
}
public void init(){
mRingPaint = new Paint();
mRingPaint.setAntiAlias(true);
mRingPaint.setStyle(Paint.Style.STROKE);
mRingPaint.setColor(mRingColor);
mProgressRingPaint = new Paint();
mProgressRingPaint.setAntiAlias(true);
mProgressRingPaint.setStyle(Paint.Style.STROKE);
mProgressRingPaint.setColor(mProgressRingColor);
mProgressRingPaint.setStrokeCap(Paint.Cap.ROUND);
}
@Override
public void onDraw(Canvas canvas){
x0 = getWidth()/2;
y0 = getHeight()/2;
mRingRadius = mRingRadius == 0 ? Math.min(getHeight()/2, getWidth()/2):mRingRadius;//没有给出属性值时,设置一个值
mRingWidth = mRingWidth == 0 ? mRingRadius/5 : mRingWidth;
//mRingRadius = mRingRadius - mRingWidth/2;//圆环真正的半径
mRingPaint.setStrokeWidth(mRingWidth);
canvas.drawCircle(x0,y0,mRingRadius,mRingPaint);
mProgressWidth = mProgressWidth == 0 ? mRingWidth/2 : mProgressWidth;
mProgressRingPaint.setStrokeWidth(mProgressWidth);
canvas.drawArc(new RectF(x0 - mRingRadius,y0 - mRingRadius,x0 + mRingRadius,y0 + mRingRadius),
startAngle,sweepAngle,false,mProgressRingPaint);
}
}