自定义控件,通过画的方式
其中既可以通过代码创建,也可以通过xml创建。
还可以对属性进行设置,更改
一、实现效果:
其中这个曲线是动图,这只截取了静止图片
二、目录结构:
三、具体代码:
waveView的代码:
package com.example.a14pxdwaveloading;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.provider.DocumentsContract;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.LinearInterpolator;
import androidx.annotation.Nullable;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.nio.file.FileSystem;
import java.nio.file.LinkOption;
import java.nio.file.WatchEvent;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;
import java.util.Iterator;
public class WaveView extends View {
private Paint mPaint;
// private android.graphics.Path mPath;
private Path mPath;
float density = getResources().getDisplayMetrics().density;
private int waveLength = (int) (100 *density);
private int waveCrest = (int) (50 * density);
//变化
private int speed;
//用于外部访问
private int lineColor = Color.BLACK; //线条的颜色
private int lineSize = 10; //线条的粗细
public WaveView(Context context) {
super(context);
init();
}
public WaveView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
//从xml中获取自定义属性的值
initAttr(context,attrs);
//初始化画笔
init();
}
private void initAttr(Context context, AttributeSet attrs){
TypedArray array = context.obtainStyledAttributes(attrs,R.styleable.WaveView);
//读取每一个属性值
waveLength = array.getInteger(R.styleable.WaveView_waveLength,(int)(100 *density));
waveCrest = array.getInteger(R.styleable.WaveView_waveCrest, (int) (50 *density));
lineColor = array.getColor(R.styleable.WaveView_lineColor, Color.BLACK);
lineSize = array.getInteger(R.styleable.WaveView_lineSize, 10);
}
private void init(){
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setColor(lineColor);
mPaint.setStrokeWidth(lineSize);
mPaint.setStyle(Paint.Style.STROKE);
}
/**
* 父容器会按照自己的规格给出一个方案
* 子View通过MeasureSpec.getMode .getSize
* 获取对应的模式和具体的尺寸
* getMode:
* Unspecified 无限制的父容器没有对这个控件进行约束
* At_Most 不能超过最大值 (wrap_content)
* Exactly 确定的值 (200dp)
* @param widthMeasureSpec
* @param heightMeasureSpec
* Match wrap 200dp
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//去除宽度的模式和预估的尺寸
int mode = MeasureSpec.getMode(widthMeasureSpec);
int width = MeasureSpec.getSize(widthMeasureSpec);
switch (mode){
case MeasureSpec.UNSPECIFIED:
System.out.println("unspecified"+width);
break;
case MeasureSpec.AT_MOST:
System.out.println("an_most"+width);
break;
case MeasureSpec.EXACTLY:
System.out.println("exactly"+width);
break;
}
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
//开始动画
startWave();
}
private void startWave(){
ValueAnimator va = ValueAnimator.ofInt(0,waveLength);
va.setDuration(500);
va.setRepeatCount(ValueAnimator.INFINITE);
va.setRepeatMode(ValueAnimator.RESTART);
va.setInterpolator(new LinearInterpolator());
va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
//获取当前值
speed = (int) valueAnimator.getAnimatedValue();
//刷新
invalidate();
}
});
va.start();
}
@Override
protected void onDraw(Canvas canvas) {
// System.out.println("here");
initPath();
canvas.drawPath(mPath,mPaint);
}
private void initPath(){
// 创建曲线
mPath = new Path();
//计算有多少个周期 (有几个完整的波)
int count = getWidth()/waveLength;
//设置起始点
mPath.moveTo(-waveLength+speed, getHeight()/2);
//获取垂直中心的坐标
int centerY = (int) getPivotY();
//确定曲线的路径
for (int start = -waveLength+speed; start < getWidth();start += waveLength){
//画上半周期
mPath.cubicTo(start, centerY,
start+waveLength/4, centerY-waveCrest,
start+waveLength/2, centerY);
//画下半周期
mPath.cubicTo(start+waveLength/2, centerY,start+waveLength*3/4,centerY+waveCrest,
start+waveLength, centerY);
}
}
public void setWaveLength(int waveLength) {
this.waveLength = waveLength;
}
public void setWaveCrest(int waveCrest) {
this.waveCrest = waveCrest;
}
public void setLineColor(int lineColor) {
this.lineColor = lineColor;
mPaint.setColor(lineColor);
}
public void setLineSize(int lineSize) {
this.lineSize = lineSize;
mPaint.setStrokeWidth(lineSize);
}
}
wave_view_attr.xml的具体代码:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="WaveView">
<attr name="lineColor" format="integer|color|reference"/>
<attr name="lineSize" format="integer"/>
<attr name="waveLength" format="integer"/>
<attr name="waveCrest" format="integer"/>
</declare-styleable>
</resources>
activity_main.xml的具体代码:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:id="@+id/root_view">
<com.example.a14pxdwaveloading.WaveView
android:layout_width="match_parent"
android:layout_height="400dp"
android:background="@color/colorPrimaryDark"
/>
</RelativeLayout>