先看效果
image.png
代码
/**
* 六边形水位效果
*/
public class SixWave extends View {
private static final float DEFAULT_AMPLITUDE_RATIO = 0.1f;
private static final float DEFAULT_AMPLITUDE_VALUE = 50.0f;
private static final float DEFAULT_WATER_LEVEL_RATIO = 0.5f;
private static final float DEFAULT_WAVE_LENGTH_RATIO = 1.0f;
private static final float DEFAULT_WAVE_SHIFT_RATIO = 0.0f;
private static final int DEFAULT_WAVE_PROGRESS_VALUE = 50;
private static final int DEFAULT_WAVE_COLOR = Color.parseColor("#212121");
private static final int DEFAULT_WAVE_BACKGROUND_COLOR = Color.parseColor("#00000000");
private static final float DEFAULT_BORDER_WIDTH = 0;
private int mCanvasSize;
private float mAmplitudeRatio;//振幅度比列大小
private int mWaveBgColor;
private int mWaveColor;
private float mDefaultWaterLevel;//默认水位等级
private float mWaterLevelRatio = 1f;//变速等级
private float mWaveShiftRatio = DEFAULT_WAVE_SHIFT_RATIO;//变速比率
private int mProgressValue = DEFAULT_WAVE_PROGRESS_VALUE;//进度
private BitmapShader mWaveShader;//水位渲染
private Matrix mShaderMatrix;//矩阵着色
private Paint mWavePaint;
private Paint mWaveBgPaint;
private Paint mBorderPaint;
private ObjectAnimator waveShiftAnim;//执行动画
private AnimatorSet mAnimatorSet;//动画组合 用来控制 暂停开始
private Context mContext;
public SixWave(final Context context) {
this(context, null);
}
public SixWave(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public SixWave(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs, defStyleAttr);
}
private void init(Context context, AttributeSet attrs, int defStyleAttr) {
mContext = context;
mShaderMatrix = new Matrix();
mWavePaint = new Paint();
mWavePaint.setAntiAlias(true);
mWaveBgPaint = new Paint();
mWaveBgPaint.setAntiAlias(true);
initAnimation();
TypedArray attributes = context.obtainStyledAttributes(attrs, R.styleable.SixWave, defStyleAttr, 0);
mWaveColor = attributes.getColor(R.styleable.SixWave_sw_waveColor, DEFAULT_WAVE_COLOR);
mWaveBgColor = attributes.getColor(R.styleable.SixWave_sw_wave_background_Color, DEFAULT_WAVE_BACKGROUND_COLOR);
mWaveBgPaint.setColor(mWaveBgColor);
float amplitudeRatioAttr = attributes.getFloat(R.styleable.SixWave_sw_waveAmplitude, DEFAULT_AMPLITUDE_VALUE) / 1000;
mAmplitudeRatio = (amplitudeRatioAttr > DEFAULT_AMPLITUDE_RATIO) ? DEFAULT_AMPLITUDE_RATIO : amplitudeRatioAttr;
mProgressValue = attributes.getInteger(R.styleable.SixWave_sw_progressValue, DEFAULT_WAVE_PROGRESS_VALUE);
setProgressValue(mProgressValue);
mBorderPaint = new Paint();
mBorderPaint.setAntiAlias(true);
mBorderPaint.setStyle(Paint.Style.STROKE);
mBorderPaint.setStrokeWidth(attributes.getDimension(R.styleable.SixWave_sw_borderWidth, dp2px(DEFAULT_BORDER_WIDTH)));
mBorderPaint.setColor(attributes.getColor(R.styleable.SixWave_sw_borderColor, DEFAULT_WAVE_COLOR));
attributes.recycle();
}
@Override
public void onDraw(Canvas canvas) {
mCanvasSize = canvas.getWidth();
if (canvas.getHeight() < mCanvasSize) {
mCanvasSize = canvas.getHeight();
}
if (mWaveShader != null) {
if (mWavePaint.getShader() == null) {
mWavePaint.setShader(mWaveShader);
}
mShaderMatrix.setScale(1, mAmplitudeRatio / DEFAULT_AMPLITUDE_RATIO, 0, mDefaultWaterLevel);
mShaderMatrix.postTranslate(mWaveShiftRatio * getWidth(),
(DEFAULT_WATER_LEVEL_RATIO - mWaterLevelRatio) * getHeight());
mWaveShader.setLocalMatrix(mShaderMatrix);
//六边形主要代码
drawPolygon(canvas);
} else {
mWavePaint.setShader(null);
}
}
private void drawPolygon(Canvas canvas) {
Path path = new Path();
float radius, centerX, centerY;
radius = centerX = centerY = Math.min(getWidth(), getHeight()) * 0.5f;
radius -= getBorderWidth() * 0.5f;
float offsetAngle = 0;
offsetAngle = (float) (Math.PI * offsetAngle / 180);
for (int i = 0; i < getSides(); i++) {
float x = (float) (centerX + radius * Math.cos(offsetAngle));
float y = (float) (centerY + radius * Math.sin(offsetAngle));
offsetAngle += 2 * Math.PI / getSides();
if (i == 0) {
path.moveTo(x, y);
} else {
path.lineTo(x, y);
}
}
path.close();
if (getSides() % 2 != 0) {
Matrix mMatrix = new Matrix();
mMatrix.postRotate(-90, centerX, centerY);
path.transform(mMatrix);
}
canvas.drawPath(path, mBorderPaint);
canvas.drawPath(path, mWavePaint);
}
private int getSides() {
return 6;//6边形
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mCanvasSize = w;
if (h < mCanvasSize) mCanvasSize = h;
updateWaveShader();
}
/**
* 初始动画
*/
private void initAnimation() {
waveShiftAnim = ObjectAnimator.ofFloat(this, "waveShiftRatio", 0f, 1f);
waveShiftAnim.setRepeatCount(ValueAnimator.INFINITE);
waveShiftAnim.setDuration(1000);
waveShiftAnim.setInterpolator(new LinearInterpolator());
mAnimatorSet = new AnimatorSet();
mAnimatorSet.play(waveShiftAnim);
}
/**
* 进度值动画
*
* @param progress
*/
public void setProgressValue(int progress) {
mProgressValue = progress;
ObjectAnimator waterLevelAnim = ObjectAnimator.ofFloat(this, "waterLevelRatio", mWaterLevelRatio, ((float) mProgressValue / 100));
waterLevelAnim.setDuration(1000);
waterLevelAnim.setInterpolator(new DecelerateInterpolator());
AnimatorSet animatorSetProgress = new AnimatorSet();
animatorSetProgress.play(waterLevelAnim);
animatorSetProgress.start();
}
/*
大波浪
*/
private void updateWaveShader() {
int width = getMeasuredWidth();
int height = getMeasuredHeight();
if (width > 0 && height > 0) {
double defaultAngularFrequency = 2.0f * Math.PI / DEFAULT_WAVE_LENGTH_RATIO / width;
float defaultAmplitude = height * DEFAULT_AMPLITUDE_RATIO;
mDefaultWaterLevel = height * DEFAULT_WATER_LEVEL_RATIO;
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
Paint wavePaint = new Paint();
wavePaint.setStrokeWidth(2);
wavePaint.setAntiAlias(true);
final int endX = width + 1;
final int endY = height + 1;
float[] waveY = new float[endX];
wavePaint.setColor(adjustAlpha(mWaveColor, 0.3f));
for (int beginX = 0; beginX < endX; beginX++) {
double wx = beginX * defaultAngularFrequency;
float beginY = (float) (mDefaultWaterLevel + defaultAmplitude * Math.sin(wx));
canvas.drawLine(beginX, beginY, beginX, endY, wavePaint);
waveY[beginX] = beginY;
}
wavePaint.setColor(mWaveColor);
final int wave2Shift = (int) ((float) width / 4);
for (int beginX = 0; beginX < endX; beginX++) {
canvas.drawLine(beginX, waveY[(beginX + wave2Shift) % endX], beginX, endY, wavePaint);
}
mWaveShader = new BitmapShader(bitmap, Shader.TileMode.REPEAT, Shader.TileMode.CLAMP);
this.mWavePaint.setShader(mWaveShader);
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = measureWidth(widthMeasureSpec);
int height = measureHeight(heightMeasureSpec);
int imageSize = (width < height) ? width : height;
setMeasuredDimension(imageSize, imageSize);
}
private int measureWidth(int measureSpec) {
int result;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
if (specMode == MeasureSpec.EXACTLY) {
result = specSize;
} else {
result = specSize;
}
return result;
}
private int measureHeight(int measureSpecHeight) {
int result;
int specMode = MeasureSpec.getMode(measureSpecHeight);
int specSize = MeasureSpec.getSize(measureSpecHeight);
if (specMode == MeasureSpec.EXACTLY) {
result = specSize;
} else {
result = specSize;
}
return (result + 2);
}
public void setWaveBgColor(int color) {
this.mWaveBgColor = color;
mWaveBgPaint.setColor(this.mWaveBgColor);
updateWaveShader();
invalidate();
}
public int getWaveBgColor() {
return mWaveBgColor;
}
public void setWaveColor(int color) {
mWaveColor = color;
updateWaveShader();
invalidate();
}
public int getWaveColor() {
return mWaveColor;
}
public void setBorderWidth(float width) {
mBorderPaint.setStrokeWidth(width);
invalidate();
}
public float getBorderWidth() {
return mBorderPaint.getStrokeWidth();
}
public void setBorderColor(int color) {
mBorderPaint.setColor(color);
updateWaveShader();
invalidate();
}
public int getBorderColor() {
return mBorderPaint.getColor();
}
public void setAmplitudeRatio(int amplitudeRatio) {
if (this.mAmplitudeRatio != (float) amplitudeRatio / 1000) {
this.mAmplitudeRatio = (float) amplitudeRatio / 1000;
invalidate();
}
}
public float getAmplitudeRatio() {
return mAmplitudeRatio;
}
public int getProgressValue() {
return mProgressValue;
}
public void setWaveShiftRatio(float waveShiftRatio) {
if (this.mWaveShiftRatio != waveShiftRatio) {
this.mWaveShiftRatio = waveShiftRatio;
invalidate();
}
}
public float getWaveShiftRatio() {
return mWaveShiftRatio;
}
public void setWaterLevelRatio(float waterLevelRatio) {
if (this.mWaterLevelRatio != waterLevelRatio) {
this.mWaterLevelRatio = waterLevelRatio;
invalidate();
}
}
public float getWaterLevelRatio() {
return mWaterLevelRatio;
}
public void startAnimation() {
if (mAnimatorSet != null) {
mAnimatorSet.start();
}
}
public void endAnimation() {
if (mAnimatorSet != null) {
mAnimatorSet.end();
}
}
public void cancelAnimation() {
if (mAnimatorSet != null) {
mAnimatorSet.cancel();
}
}
@TargetApi(Build.VERSION_CODES.KITKAT)
@SuppressWarnings("deprecation")
public void pauseAnimation() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
if (mAnimatorSet != null) {
mAnimatorSet.pause();
}
}
}
@TargetApi(Build.VERSION_CODES.KITKAT)
@SuppressWarnings("deprecation")
public void resumeAnimation() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
if (mAnimatorSet != null) {
mAnimatorSet.resume();
}
}
}
public void setAnimDuration(long duration) {
waveShiftAnim.setDuration(duration);
}
@Override
protected void onAttachedToWindow() {
startAnimation();
super.onAttachedToWindow();
}
@Override
protected void onDetachedFromWindow() {
cancelAnimation();
super.onDetachedFromWindow();
}
private int adjustAlpha(int color, float factor) {
int alpha = Math.round(Color.alpha(color) * factor);
int red = Color.red(color);
int green = Color.green(color);
int blue = Color.blue(color);
return Color.argb(alpha, red, green, blue);
}
private int dp2px(float dp) {
final float scale = mContext.getResources().getDisplayMetrics().density;
return (int) (dp * scale + 0.5f);
}
}
attrs
<declare-styleable name="SixWave">
<attr name="sw_borderWidth" format="dimension" />
<attr name="sw_borderColor" format="color" />
<attr name="sw_progressValue" format="integer" />
<attr name="sw_waveColor" format="color" />
<attr name="sw_wave_background_Color" format="color" />
<attr name="sw_waveAmplitude" format="float" />
</declare-styleable>
xml
<com.example.kotlin.widget.SixWave
android:id="@+id/sixWave"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:sw_borderColor="@color/colorAccent"
app:sw_borderWidth="3dp"
app:sw_progressValue="70"
app:sw_waveAmplitude="50"
app:sw_waveColor="@color/colorAccent" />
activity
override fun initData() {
// sixWave.setBorderColor(Color.BLUE)
// sixWave.setWaveColor(Color.BLUE)
// sixWave.setWaveBgColor(Color.TRANSPARENT)
// sixWave.setAmplitudeRatio(40)
// sixWave.setWaveShiftRatio(0.2f)
// sixWave.setProgressValue(70)
sixWave.setAnimDuration(3000)
}
六边形图形效果根据WaveLoadingView修改。可以改多种样式,三角形,正方形,矩形,圆形,圆角矩形
WaveLoadingView传送门Github地址
网友评论