package com.qiao.atc.custom.view.path;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Shader;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;
import com.qiao.atc.R;
/**
* Created by qiao9 on 2018/6/14.
* 波浪图形
*/
public class WaveView extends View {
/**
* +------------------------+
* |<--wave length-> |______
* | /\ | /\ | |
* | / \ | / \ | amplitude
* | / \ | / \ | |
* |/ \ |/ \|__|____
* | \ / | |
* | \ / | |
* | \ / | |
* | \/ | water level
* | | |
* | | |
* +------------------------+__|____
*/
//默认振幅比
private static final float DEFAULT_AMPLITUDE_RATIO = 0.06f;
//默认水位比
private static final float DEFAULT_WATER_LEVEL_RATIO = 0.5f;
//默认波长比
private static final float DEFAULT_WAVE_LENGTH_RATIO = 0.5f;
//默认波转变比率
private static final float DEFAULT_WAVE_SHIFT_RATIO = 0.0f;
//默认后面的波颜色
public static int DEFAULT_BEHIND_WAVE_COLOR;
//默认前面的波颜色
public static int DEFAULT_FRONT_WAVE_COLOR;
public static final ShapeType DEFAULT_WAVE_SHAPE = ShapeType.SQUARE;
//如果为真则显示波浪
private boolean mShowWave;
//着色漆包含的重复的波形
private BitmapShader mWaveShader;
//矩阵
private Matrix mShaderMatrix;
//Wave画笔
private Paint mViewPaint;
//边线画笔
private Paint mBorderPaint;
//默认振幅
private float mDefaultAmplitude;
//默认水位
private float mDefaultWaterLevel;
//默认波长
private float mDefaultWaveLenght;
//默认角频率
private double mDefaultAngularFrequency;
//振幅比
private float mAmplitudeRatio = DEFAULT_AMPLITUDE_RATIO;
//波长比
private float mWaveLenghtRatio = DEFAULT_WAVE_LENGTH_RATIO;
//水位比
private float mWaterLevelRatio = DEFAULT_WATER_LEVEL_RATIO;
//波转比率
private float mWaveShiftRatio = DEFAULT_WAVE_SHIFT_RATIO;
//颜色啊
private int mBehindWaveColor = DEFAULT_BEHIND_WAVE_COLOR;
private int mFrontWaveColor = DEFAULT_FRONT_WAVE_COLOR;
public enum ShapeType {
CIRCLE,
SQUARE
}
private ShapeType mShapeType = DEFAULT_WAVE_SHAPE;
public WaveView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public WaveView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
mShaderMatrix = new Matrix();
mViewPaint = new Paint();
mViewPaint.setAntiAlias(true);
TypedArray array = context.getTheme().obtainStyledAttributes(attrs, R.styleable.ScrollCircleColorChange, 0, 0);
mBehindWaveColor = array.getColor(R.styleable.ScrollCircleColorChange_firstColor, Color.parseColor("#069adc"));
mFrontWaveColor = array.getColor(R.styleable.ScrollCircleColorChange_secondColor, Color.parseColor("#41c1f4"));
array.recycle();
}
public void setFirstColor(int firstColor) {
DEFAULT_FRONT_WAVE_COLOR = firstColor;
}
public void setThreeColor(int threeColor) {
// mThreeColor = threeColor;
}
public void setSecondColor(int sceondColor) {
DEFAULT_BEHIND_WAVE_COLOR = sceondColor;
}
public float getWaveShiftRatio() {
return mWaveShiftRatio;
}
/**
* 根据波转化比移动波形
*
* @param waveShiftRatio 变换范围0~1,默认为0
* 波变换比的结果,波的倍数,宽度是要移的长度。
*/
public void setWaveShiftRatio(float waveShiftRatio) {
if (mWaveShiftRatio != waveShiftRatio) {
mWaveShiftRatio = waveShiftRatio;
invalidate();
}
}
public float getWaterLevelRatio() {
return mWaterLevelRatio;
}
/**
* 根据水位比设置水位
*
* @param waterLevelRatio Should be 0 ~ 1. Default to be 0.5.
* <br/>Ratio of water level to WaveView height.
*/
public void setWaterLevelRatio(float waterLevelRatio) {
if (mWaterLevelRatio != waterLevelRatio) {
mWaterLevelRatio = waterLevelRatio;
invalidate();
}
}
public float getAmplitudeRatio() {
return mAmplitudeRatio;
}
/**
* 根据振幅比设置波的波动大小
*
* @param amplitudeRatio 默认是0.05 放大倍数+水平度数应该小于1
* 波图振幅与高度之比
*/
public void setAmplitudeRatio(float amplitudeRatio) {
if (mAmplitudeRatio != amplitudeRatio) {
mAmplitudeRatio = amplitudeRatio;
invalidate();
}
}
public float getWaveLengthRatio() {
return mWaveLenghtRatio;
}
public void setWaveLengthRatio(float waveLengthRatio) {
mWaveLenghtRatio = waveLengthRatio;
}
/**
* 判断波是否显示
*
* @return
*/
public boolean isShowWave() {
return mShowWave;
}
/**
* 设置是否显示波
*
* @param showWave
*/
public void setShowWave(boolean showWave) {
mShowWave = showWave;
}
/**
* 设置边缘线条画笔
*
* @param width 画笔宽度
* @param color 画笔颜色
*/
public void setBorder(int width, int color) {
if (mBorderPaint == null) {
mBorderPaint = new Paint();
mBorderPaint.setAntiAlias(true);
mBorderPaint.setStyle(Paint.Style.STROKE);
}
mBorderPaint.setColor(color);
mBorderPaint.setStrokeWidth(width);
invalidate();
}
/**
* 在控件大小发生改变时会调用,初始化会调用一次
*
* @param w
* @param h
* @param oldw
* @param oldh
*/
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
createShader();
}
/**
* 创建带有默认波浪的着色器,水平重复,垂直夹住
*/
private void createShader() {
if (getWidth() == 0 || getHeight() == 0) {
return;
}
mBehindWaveColor = DEFAULT_BEHIND_WAVE_COLOR;
mFrontWaveColor = DEFAULT_FRONT_WAVE_COLOR;
mDefaultAngularFrequency = 2.0f * Math.PI / DEFAULT_WAVE_LENGTH_RATIO / getWidth();
mDefaultAmplitude = getHeight() * DEFAULT_AMPLITUDE_RATIO;
mDefaultWaterLevel = getHeight() * 0.8f;
mDefaultWaveLenght = getWidth();
Bitmap bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
Paint wavePaint = new Paint();
wavePaint.setStrokeWidth(1);
wavePaint.setAntiAlias(true);
//在位图中绘制默认波//y=Asin(ωx+φ)+h
final int endX = getWidth() - 1;
// final int endY = getHeight() + 1;
float[] waveY = new float[endX];
wavePaint.setColor(mBehindWaveColor);
for (int beginX = 0; beginX < endX; beginX++) {
double wx = beginX * mDefaultAngularFrequency;
float beginY = (float) (mDefaultAmplitude + mDefaultWaterLevel * Math.sin(wx));
// canvas.drawLine(beginX,beginY,beginX,endY,wavePaint);
canvas.drawLine(beginX, 0, beginX, beginY, wavePaint);
waveY[beginX] = beginY;
}
wavePaint.setColor(mFrontWaveColor);
final int wave2Shift = (int) (mDefaultWaveLenght / 8);
for (int beginX = 0; beginX < endX; beginX++) {
// canvas.drawLine(beginX, waveY[(beginX + wave2Shift) % endX], beginX, endY, wavePaint);
canvas.drawLine(beginX, 0, beginX, waveY[(beginX + wave2Shift) % endX], wavePaint);
}
wavePaint.setColor(mFrontWaveColor);
wavePaint.setAlpha(60);
final int wave3Shift = (int) (mDefaultWaveLenght / 3);
for (int beginX = 0; beginX < endX; beginX++) {
// canvas.drawLine(beginX, waveY[(beginX + wave2Shift) % endX], beginX, endY, wavePaint);
canvas.drawLine(beginX, 0, beginX, waveY[(beginX + wave3Shift) % endX], wavePaint);
}
//使用位图创建着色器
mWaveShader = new BitmapShader(bitmap, Shader.TileMode.REPEAT, Shader.TileMode.CLAMP);
mViewPaint.setShader(mWaveShader);
}
@Override
protected void onDraw(Canvas canvas) {
//根据shader的状态修改着色器
if (mShowWave && mWaveShader != null) {
//首先调用showWave之后,将其分配给画笔
if (mViewPaint.getShader() == null) {
mViewPaint.setShader(mWaveShader);
}
//将矩阵设置为根据波长比和振幅比来缩放//这决定了波浪的大小
mShaderMatrix.setScale(mWaveLenghtRatio / DEFAULT_WAVE_LENGTH_RATIO, mAmplitudeRatio / DEFAULT_AMPLITUDE_RATIO, 0, mDefaultWaterLevel);
//用指定的波转比和水位比来处理矩阵//这决定了波浪的起始位置
//mShaderMatrix.postTranslate(mWaveShiftRatio * getWidth(), (DEFAULT_WATER_LEVEL_RATIO - mWaterLevelRatio) * getHeight());
//M' = T(dx, dy) * M
mShaderMatrix.postTranslate(mWaveShiftRatio * getWidth(), (0.1f) * getHeight());
//设置着色器的局部矩阵
mWaveShader.setLocalMatrix(mShaderMatrix);
float borderWidth = mBorderPaint == null ? 0f : mBorderPaint.getStrokeWidth();
switch (mShapeType) {
case CIRCLE:
if (borderWidth > 0) {
canvas.drawCircle(getWidth() / 2f, getHeight() / 2f, (getWidth() - borderWidth) / 2f - 1f, mBorderPaint);
}
float radius = getWidth() / 2f - borderWidth;
canvas.drawCircle(getWidth() / 2f, getHeight() / 2f, radius, mViewPaint);
break;
case SQUARE:
if (borderWidth > 0) {
canvas.drawRect(borderWidth / 2f, borderWidth / 2f, getWidth() - borderWidth / 2f - 0.5f, getHeight() - borderWidth / 2f - 0.5f, mBorderPaint);
}
canvas.drawRect(borderWidth, borderWidth, getWidth() - getHeight(), getHeight() - borderWidth, mViewPaint);
break;
}
} else {
mViewPaint.setShader(null);
}
}
}