申明
- 本片文章大主要就是手动写一遍用来加深下印象,真想学技术还是移步下面的资料链接;
- 参考资料:
https://www.jianshu.com/p/7bfaf8789e5f 自定义View(一)
自定义view简单流程
- 流程不复杂,特别如果是效果简单就很快。
流程
- 尝试写一个自定义view,一个加载动画。
- 一个加载loading动画的view,一个圆形或者长方形的加载框,边框一开始是完整的,然后顺时针开始消失,到完全消失的时候开始出现框中间是自己定义的加载图片或者文字。
自定义属性声明和使用
- 分析确认自己view的属性(长高,颜色,字体,大小)
/**
* 圆形的半径
*/
private int radius = -1;
/**
* 加载框的颜色
*/
private int cheek_color = Color.BLACK;
/**
* 加载狂中间的图片
*/
private long imageResId = R.mipmap.ic_launcher;
/**
* 加载框中间的文字
*/
private String loadingText = "加载中...";
/**
* 文字字体大小
*/
private int textSize = 1;
private int height;
private int width;
/**
* 圆形图形的进度
*/
private int progress = 5;
private int maxProgress = 100;
private int progressColor = Color.BLACK;
private int backColor = Color.WHITE;
private Paint paint = new Paint();
;
private RectF rectF = new RectF();
- 在res/values/目录下创建attrs.xml并定义自己view属性
<declare-styleable name="LoadingView">
<attr name="text" format="string"/>
<attr name="textSize" format="dimension"/>
<attr name="mode" format="enum">
<enum name="circle" value="0"/>
<enum name="rectangle" value="1"/>
</attr>
<attr name="cheek_color" format="color"/>
<attr name="imageRes" format="integer"/>
<attr name="radius" format="dimension"/>
</declare-styleable>
- 在layout文件中使用
<com.southwind.selfview.view.LoadingView
android:id="@+id/loading"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:mode="circle"
app:radius="30dp"
android:text="加载中..."
app:textSize="12dp"
app:cheek_color="@color/black"
android:layout_width="100dp"
android:layout_height="80dp"/>
- 在view构造方法里面获取
public LoadingView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.LoadingView);
mode = array.getInteger(R.styleable.LoadingView_mode, 0);
cheek_color = array.getColor(R.styleable.LoadingView_cheek_color, Color.BLACK);
textSize = array.getDimensionPixelSize(R.styleable.LoadingView_textSize, (int) dip2px(13));
imageResId = array.getResourceId(R.styleable.LoadingView_imageRes, -1);
radius = array.getDimensionPixelSize(R.styleable.LoadingView_radius, (int) dip2px(5));
backColor = Color.BLACK;
progressColor = Color.WHITE;
}
onMeasure确定view的大小尺寸
- 这里我没做任何调整,也是不熟练,还得看看,以后专门学了在写一篇
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
height = MeasureSpec.getSize(heightMeasureSpec);
width = MeasureSpec.getSize(widthMeasureSpec);
setMeasuredDimension(width, height);
}
onDraw画出你要的效果
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
// canvas.drawPaint(paint);
//设置画笔属性
paint.setStyle(Paint.Style.FILL);
paint.setAntiAlias(true);
//原始进度
radius = Math.min(width, height) - 40;
//画出进度圆形
paint.setColor(backColor);
rectF.left = (width - radius) / 2;//左边距:(空间宽度-直径)/2
rectF.right = radius + (width - radius) / 2;
rectF.top = (height - radius) / 2;
rectF.bottom = radius + (width - radius) / 2;
canvas.drawArc(rectF, 270, 360, false, paint);
//首先画出当前进度的圆形
radius = Math.min(width, height) - 38;
//画出进度圆形
paint.setColor(progressColor);
rectF.left = (width - radius) / 2;//左边距:(空间宽度-直径)/2
rectF.right = radius + (width - radius) / 2;
rectF.top = (height - radius) / 2;
rectF.bottom = radius + (width - radius) / 2;
//计算进度
float precent = (float) progress / (float) maxProgress;
float sweepAngle = (float) (360 * precent);
canvas.drawArc(rectF, 270, sweepAngle, false, paint);
//画出遮挡圆形
int radius2 = radius - 10;
paint.setColor(Color.WHITE);
rectF.left = (width - radius2) / 2;//左边距:(空间宽度-直径)/2
rectF.right = radius2 + (width - radius2) / 2;
rectF.top = (height - radius2) / 2;
rectF.bottom = radius2 + (width - radius2) / 2;
canvas.drawArc(rectF, 0, 360, false, paint);
canvas.drawArc(rectF, 0, 360, false, paint);
//画出text
paint.setColor(Color.BLACK);
paint.setTextSize(22);
canvas.drawText(loadingText,width/2 - 40,height/2 + 20,paint);
}
其他处理
- 这里主要就是做了个循环的东西,必须要在外部开启,说实话内部不确定在哪里开启哈,肯定不能在onDraw中开启,要不然肯定会重复调用
/**
* 实时设置当前进度取重绘
*
*/
private void setCurrentProgress() {
invalidate();
}
public void startLoading(){
CirculateThread runnable = new CirculateThread();
Thread thread = new Thread(runnable);
thread.start();
}
class CirculateThread implements Runnable {
@Override
public void run() {
while (true) {
if (progress < 100) {
progress += 2;
} else {
progress = 0;
int color = progressColor;
progressColor = backColor;
backColor = color;
}
try {
Thread.sleep(50);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
setCurrentProgress();
}
}
}
- 使用
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
LoadingView view = this.findViewById(R.id.loading);
view.startLoading();
}
效果
- 这个是最简单的流程哈,等我再学习学习搞个更吊的出来。
-
要查看原图才能看的gif不是好gif
流程很简单哈
- 这里面最重要的就是onMeasure和onDraw,一个确定你的布局大小相关,一个确实的画出你的view的东西。
- 好多要学习的,只能说任重而道远吧。