先上效果图
自定义代码如下:
package com.langteng.courtesy.customview; import android.content.Context; 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.util.AttributeSet; import android.view.View; //作者: 冯浩 on 2019/1/23 09:36 // _ooOoo_ // o8888888o // 88" . "88 // (| ^_^ |) // O\ = /O // ____/`---'\____ // .' \\| |// `. // / \\||| : |||// \ // / _||||| -:- |||||- \ // | | \\\ - /// | | // | \_| ''\---/'' | | // \ .-\__ `-` ___/-. / // ___`. .' /--.--\ `. . ___ // ."" '< `.___\_<|>_/___.' >'"". // | | : `- \`.;`\ _ /`;.`/ - ` : | | // \ \ `-. \_ __\ /__ _/ .-` / / // ========`-.____`-.___\_____/___.-`____.-'======== // `=---=' // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ // 佛祖保佑 永无BUG 永不修改 // 程序员之歌 作者:冯浩(字:德明) // 十年生死两茫茫 ,写程序,到天亮。 // 千行代码 ,Bug何处藏 ? // 纵使上线又怎样 ,朝令改 ,夕断肠。 // // 领导每天新想法 ,日日改 ,夜夜忙。 // 相顾无言 ,唯有泪千行。 // 每晚灯火阑珊处 ,夜难寐 ,加班狂。 // ************************************************************************************************ public class WaveProgressView extends View { private static final float DEFAULT_AMPLITUDE_RATIO = 0.05f; 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; public static final int DEFAULT_BEHIND_WAVE_COLOR = Color.parseColor("#28FFFFFF"); public static final int DEFAULT_FRONT_WAVE_COLOR = Color.parseColor("#3CFFFFFF"); public static final ShapeType DEFAULT_WAVE_SHAPE = ShapeType.CIRCLE; private boolean showBehindLine = true; public enum ShapeType { CIRCLE, SQUARE } // if true, the shader will display the wave private boolean mShowWave; // shader containing repeated waves private BitmapShader mWaveShader; // shader matrix private Matrix mShaderMatrix; // paint to draw wave private Paint mViewPaint; // paint to draw border private Paint mBorderPaint;//边界画笔 // paint to draw backgroup private Paint mBgPaint; //背景画笔 private float mDefaultAmplitude; private float mDefaultWaterLevel; private float mDefaultWaveLength; private double mDefaultAngularFrequency; private float mAmplitudeRatio = DEFAULT_AMPLITUDE_RATIO; private float mWaveLengthRatio = 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; private ShapeType mShapeType = DEFAULT_WAVE_SHAPE; public WaveProgressView(Context context) { super(context); init(); } public WaveProgressView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public WaveProgressView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(); } private void init() { mShaderMatrix = new Matrix(); mViewPaint = new Paint(); mViewPaint.setAntiAlias(true); mBgPaint = new Paint(); mBgPaint.setAntiAlias(true); /**默认背景色---淡黄色*/ mBgPaint.setColor(0xff282828); } public float getWaveShiftRatio() { return mWaveShiftRatio; } /** * Shift the wave horizontally according to <code>waveShiftRatio</code>. * * @param waveShiftRatio Should be 0 ~ 1. Default to be 0. * <br/>Result of waveShiftRatio multiples width of WaveView is the length to shift. */ public void setWaveShiftRatio(float waveShiftRatio) { if (mWaveShiftRatio != waveShiftRatio) { mWaveShiftRatio = waveShiftRatio; invalidate(); } } public float getWaterLevelRatio() { return mWaterLevelRatio; } /** * Set water level according to <code>waterLevelRatio</code>. * * @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; } /** * Set vertical size of wave according to <code>amplitudeRatio</code> * * @param amplitudeRatio Default to be 0.05. Result of amplitudeRatio + waterLevelRatio should be less than 1. * <br/>Ratio of amplitude to height of WaveView. */ public void setAmplitudeRatio(float amplitudeRatio) { if (mAmplitudeRatio != amplitudeRatio) { mAmplitudeRatio = amplitudeRatio; invalidate(); } } public float getWaveLengthRatio() { return mWaveLengthRatio; } /** * Set horizontal size of wave according to <code>waveLengthRatio</code> * * @param waveLengthRatio Default to be 1. * <br/>Ratio of wave length to width of WaveView. */ public void setWaveLengthRatio(float waveLengthRatio) { mWaveLengthRatio = waveLengthRatio; } public boolean isShowWave() { return mShowWave; } public void setShowWave(boolean showWave) { mShowWave = showWave; } 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(); } public void setWaveColor(int behindWaveColor, int frontWaveColor) { mBehindWaveColor = behindWaveColor; mFrontWaveColor = frontWaveColor; if (getWidth() > 0 && getHeight() > 0) { // need to recreate shader when color changed mWaveShader = null; createShader(); invalidate(); } } public void setShapeType(ShapeType shapeType) { mShapeType = shapeType; invalidate(); } public void setShowBehindLine(boolean showBehindLine){ this.showBehindLine = showBehindLine; invalidate(); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); createShader(); } /** * Create the shader with default waves which repeat horizontally, and clamp vertically */ private void createShader() { mDefaultAngularFrequency = 2.0f * Math.PI / DEFAULT_WAVE_LENGTH_RATIO / getWidth(); mDefaultAmplitude = getHeight() * DEFAULT_AMPLITUDE_RATIO; mDefaultWaterLevel = getHeight() * DEFAULT_WATER_LEVEL_RATIO; mDefaultWaveLength = getWidth(); Bitmap bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); Paint wavePaint = new Paint(); wavePaint.setStrokeWidth(2); wavePaint.setAntiAlias(true); // Draw default waves into the bitmap // 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) (mDefaultWaterLevel + mDefaultAmplitude * Math.sin(wx)); if(showBehindLine){ canvas.drawLine(beginX, beginY, beginX, endY, wavePaint); } waveY[beginX] = beginY; } wavePaint.setColor(mFrontWaveColor); final int wave2Shift = (int) (mDefaultWaveLength / 4); for (int beginX = 0; beginX < endX; beginX++) { canvas.drawLine(beginX, waveY[(beginX + wave2Shift) % endX], beginX, endY, wavePaint); } // use the bitamp to create the shader mWaveShader = new BitmapShader(bitmap, Shader.TileMode.REPEAT, Shader.TileMode.CLAMP); mViewPaint.setShader(mWaveShader); } @Override protected void onDraw(Canvas canvas) { // modify paint shader according to mShowWave state if (mShowWave && mWaveShader != null) { // first call after mShowWave, assign it to our paint if (mViewPaint.getShader() == null) { mViewPaint.setShader(mWaveShader); } // sacle shader according to mWaveLengthRatio and mAmplitudeRatio // this decides the size(mWaveLengthRatio for width, mAmplitudeRatio for height) of waves mShaderMatrix.setScale( mWaveLengthRatio / DEFAULT_WAVE_LENGTH_RATIO, mAmplitudeRatio / DEFAULT_AMPLITUDE_RATIO, 0, mDefaultWaterLevel); // translate shader according to mWaveShiftRatio and mWaterLevelRatio // this decides the start position(mWaveShiftRatio for x, mWaterLevelRatio for y) of waves mShaderMatrix.postTranslate( mWaveShiftRatio * getWidth(), (DEFAULT_WATER_LEVEL_RATIO - mWaterLevelRatio) * getHeight()); // assign matrix to invalidate the shader 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, mBgPaint); 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() - borderWidth, getHeight() - borderWidth, mViewPaint); break; } } else { mViewPaint.setShader(null); } } }
//布局中代码
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="@dimen/x162" android:layout_height="wrap_content" android:layout_margin="@dimen/x30"> <RelativeLayout android:id="@+id/coiner" android:layout_width="@dimen/x162" android:layout_height="@dimen/x162"> <com.langteng.courtesy.customview.WaveProgressView android:id="@+id/progress" android:layout_width="@dimen/x162" android:layout_height="@dimen/x162" /> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:orientation="horizontal"> <TextView android:id="@+id/first_tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="4" android:textColor="#FFFFFFFF" android:textSize="@dimen/x54" /> <TextView android:id="@+id/second_tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text=".35" android:textColor="#FFFFFFFF" android:textSize="@dimen/x36" /> </LinearLayout> </RelativeLayout> <TextView android:gravity="center" android:id="@+id/job_tv" android:layout_width="@dimen/x162" android:layout_height="wrap_content" android:layout_below="@id/coiner" android:layout_centerHorizontal="true" android:layout_marginTop="@dimen/y30" android:ellipsize="end" android:maxLines="2" android:text="哈设计师" android:textColor="#FFFFFFFF" android:textSize="@dimen/x40" /> </RelativeLayout>
//界面中动态改变数值以及颜色
WaveProgressView mWaveProgressView = (WaveProgressView) helper.getView(R.id.progress); mWaveProgressView.setShapeType(WaveProgressView.ShapeType.CIRCLE); /**绘制边界线的宽及颜色,不需要的可以注销,此处默认宽4,白色*/ mWaveProgressView.setBorder(4, 0xffffffff); /**是否显示双线*/ mWaveProgressView.setShowBehindLine(false); mWaveHelper = new WaveHelper(mWaveProgressView); // mWaveProgressView.setWaterLevelRatio(0.1F); mWaveProgressView.setWaterLevelRatio(Float.parseFloat(item.getProportion()) / 100f); mWaveHelper.start(); if (helper.getPosition() > getArgb().size()) { mWaveProgressView.setWaveColor( Color.parseColor("#fff7bfc0"),//波浪线上(淡紫色)setShowBehindLine为true时显示,false不显示 getArgb().get(helper.getPosition() - getArgb().size()));//波浪线下(橘黄色) } else { mWaveProgressView.setWaveColor( Color.parseColor("#fff7bfc0"),//波浪线上(淡紫色)setShowBehindLine为true时显示,false不显示 getArgb().get(helper.getPosition()));//波浪线下(橘黄色) } } private List<Integer> getArgb() { List<Integer> argbs = new ArrayList<>(); argbs.add(Color.argb(255, 253, 177, 49)); argbs.add(Color.argb(255, 126, 185, 255)); argbs.add(Color.argb(255, 80, 227, 194)); argbs.add(Color.argb(255, 255, 94, 98)); argbs.add(Color.argb(255, 157, 221, 85)); argbs.add(Color.argb(255, 198, 158, 255)); return argbs; }