水波浪贝塞尔效果(六边形)

2019-09-30  本文已影响0人  涂涂家的小七呀

先看效果


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地址

上一篇下一篇

猜你喜欢

热点阅读