自定義某多多跑馬燈廣告圈

不多廢話,先行上圖


 

代碼:

public class MddPmdView extends View {

    private Paint mPaint = null;
    private int mW = 0;
    private int mH = 0;
    /**
     * 背景圓角半徑
     */
    private float mRadiu = 0;
    /**
     * 邊框線寬度
     */
    private float mStockWidth = 0;
    /**
     * 點半徑
     */
    private float mCirlRadiu = 0;
    /**
     * 背景顏色
     */
    private int mBgColor = Color.BLACK;
    /**
     * 邊框線顏色
     */
    private int mStockColor = 0xffd88341;
    /**
     * 線上點的個數
     */
    private int mPointCount = 0;

    private long duration = 0;
    private List<PointF> mPoints = new ArrayList<>();
    private List<Integer> colors = new ArrayList<>();
    private Disposable mDisposable;
    private int mRunIndex = -1;

    public MddPmdView(Context context) {
        this(context, null);
    }

    public MddPmdView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MddPmdView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initDatas(context, attrs);
    }

    private void initDatas(Context context, AttributeSet attrs) {
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MddPmdView);
        mBgColor = a.getInt(R.styleable.MddPmdView_pmdBgColor, Color.GRAY);
        mCirlRadiu = DeviceUtil.dip2px(context, a.getInt(R.styleable.MddPmdView_pmdCirlRadiu, 0));
        mStockColor = a.getColor(R.styleable.MddPmdView_pmdStockColor, 0xfff3a33c);
        mRadiu = DeviceUtil.dip2px(context, a.getInt(R.styleable.MddPmdView_pmdRadiu, 0));
        mStockWidth = DeviceUtil.dip2px(context, a.getInt(R.styleable.MddPmdView_pmdStockWidth, 0));
        mPointCount = a.getInt(R.styleable.MddPmdView_pmdPointCount, 0);
        duration = a.getInt(R.styleable.MddPmdView_pmdDuration, 300);
        a.recycle();
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        colors.add(Color.RED);
        colors.add(Color.YELLOW);
        colors.add(Color.BLUE);
        colors.add(Color.GREEN);
    }

    /**
     * 計算數據(線上的所有點)
     */
    private void loadDatas() {
        mPoints.clear();
        if (mPointCount <= 0 || mW <= 0 || mH <= 0) {
            return;
        }
        float nCirl = (float) (Math.PI * mRadiu);//圓長度
        float nTotalLengh = nCirl + mW * 2 + mH * 2 - mRadiu * 8;//內圈總長度
        float nMult = nTotalLengh / mPointCount;
        List<Integer> sizes = new ArrayList<>();

        //上邊
        float w1 = mW - mRadiu * 2;
        float y = w1 % nMult;//每條邊計算完成後的餘值
        int size = (int) ((w1 - y) / nMult);
        sizes.add(size);
        PointF nFirstPoint = new PointF();//起始位置,第一個點
        nFirstPoint.x = mRadiu;
        nFirstPoint.y = mRadiu / 2;
        mPoints.add(nFirstPoint);
        for (int i = 0; i < size; i++) {
            //上邊時  第一個點爲計算的起點,之後的點Y左邊與起點相等,X爲根據單位遞加
            PointF point = new PointF();
            point.y = mRadiu / 2;
            point.x = mRadiu + (i + 1) * nMult;
            mPoints.add(point);
        }
        float offset = y;//主要用於下一條邊計算
        double nA = -90;

        //右上圓弧
        float w2 = nCirl / 4 + y;
        y = w2 % nMult;
        size = (int) ((w2 - y) / nMult);
        sizes.add(size);
        for (int i = 0; i < size; i++) {
            float nw = nMult - offset;//計算圓弧上的長度
            offset = 0;

            nA += nw * 90 / (nCirl / 4);//根據長度  計算角度
            PointF point = new PointF();
            point.x = mW - mRadiu + (float) (mRadiu / 2 * Math.cos(nA * Math.PI / 180));
            point.y = mRadiu + (float) (mRadiu / 2 * Math.sin(nA * Math.PI / 180));
            mPoints.add(point);
        }
        offset = y;

        //右邊
        float w3 = mH - mRadiu * 2 + y;
        y = w3 % nMult;
        size = (int) ((w3 - y) / nMult);
        sizes.add(size);
        for (int i = 0; i < size; i++) {
            PointF point = new PointF();
            point.x = mW - mRadiu / 2;
            if (i == 0) {
                point.y = mRadiu + nMult - offset;
            } else {
                point.y = mPoints.get(mPoints.size() - 1).y + nMult;
            }
            mPoints.add(point);
        }
        offset = y;

        //右下圓弧
        float w4 = nCirl / 4 + y;
        y = w4 % nMult;
        size = (int) ((w4 - y) / nMult);
        sizes.add(size);
        nA = 0;
        for (int i = 0; i < size; i++) {
            float nw = nMult - offset;
            offset = 0;
            nA += nw * 90 / (nCirl / 4);//根據長度  計算角度
            PointF point = new PointF();
            point.x = mW - mRadiu + (float) (mRadiu / 2 * Math.cos(nA * Math.PI / 180));
            point.y = mH - mRadiu + (float) (mRadiu / 2 * Math.sin(nA * Math.PI / 180));
            mPoints.add(point);
        }
        offset = y;

        //下邊
        float w5 = mW - mRadiu * 2 + y;
        y = w5 % nMult;
        size = (int) ((w5 - y) / nMult);
        sizes.add(size);
        for (int i = 0; i < size; i++) {
            PointF point = new PointF();
            point.y = mH - mRadiu / 2;
            if (i == 0) {
                point.x = mW - mRadiu - (nMult - offset);
            } else {
                point.x = mPoints.get(mPoints.size() - 1).x - nMult;
            }
            mPoints.add(point);
        }
        offset = y;

        //左下圓弧
        float w6 = nCirl / 4 + y;
        y = w6 % nMult;
        size = (int) ((w6 - y) / nMult);
        sizes.add(size);
        nA = 90;
        for (int i = 0; i < size; i++) {
            float nw = nMult - offset;
            offset = 0;
            nA += nw * 90 / (nCirl / 4);//根據長度  計算角度
            PointF point = new PointF();
            point.x = mRadiu + (float) (mRadiu / 2 * Math.cos(nA * Math.PI / 180));
            point.y = mH - mRadiu + (float) (mRadiu / 2 * Math.sin(nA * Math.PI / 180));
            mPoints.add(point);
        }
        offset = y;

        //左邊
        float w7 = mH - mRadiu * 2 + y;
        y = w7 % nMult;
        size = (int) ((w7 - y) / nMult);
        sizes.add(size);
        for (int i = 0; i < size; i++) {
            PointF point = new PointF();
            point.x = mRadiu / 2;
            if (i == 0) {
                point.y = mH - mRadiu - (nMult - offset);
            } else {
                point.y = mPoints.get(mPoints.size() - 1).y - nMult;
            }
            mPoints.add(point);
        }
        offset = y;

        //左上圓弧
        float w8 = nCirl / 4 + y;
        y = w8 % nMult;
        size = (int) ((w8 - y) / nMult);
        sizes.add(size);
        nA = 180;
        for (int i = 0; i < size; i++) {
            float nw = nMult - offset;
            offset = 0;
            nA += nw * 90 / (nCirl / 4);//根據長度  計算角度
            PointF point = new PointF();
            point.x = mRadiu + (float) (mRadiu / 2 * Math.cos(nA * Math.PI / 180));
            point.y = mRadiu + (float) (mRadiu / 2 * Math.sin(nA * Math.PI / 180));
            mPoints.add(point);
        }
        sizes.clear();
    }

    /**
     * 入口,開始繪製
     *
     * @param width  總寬
     * @param height 總高
     */
    public void startRun(int width, int height) {
        mW = width;
        mH = height;
        if (mDisposable != null && !mDisposable.isDisposed()) {
            mDisposable.dispose();
        }
        loadDatas();
        mDisposable = Observable.intervalRange(0, Integer.MAX_VALUE, 0, duration, TimeUnit.MILLISECONDS)
                .subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Consumer<Long>() {
                    @Override
                    public void accept(final Long aLong) throws Exception {
                        try {
                            mRunIndex += 1;
                            invalidate();
                        } catch (Exception e) {
                            Log.e("Tag", Log.getStackTraceString(e));
                        }
                    }
                });
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (mPoints.isEmpty()) {
            //無數據時不繪製
            return;
        }
        mPaint.setColor(mBgColor);
        mPaint.setStyle(Paint.Style.FILL);
        canvas.drawRoundRect(new RectF(0, 0, mW, mH), mRadiu, mRadiu, mPaint);//畫背景

        mPaint.setColor(mStockColor);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeWidth(mStockWidth);
        RectF rect = new RectF(mRadiu / 2, mRadiu / 2, mW - mRadiu / 2, mH - mRadiu / 2);
        canvas.drawRoundRect(rect, mRadiu / 2, mRadiu / 2, mPaint);
        //畫邊線,此時rect的四條邊的值,爲實際效果4條邊的中心值,即爲邊線寬度1時的位置,大於1時則以1爲中心

        mPaint.setStyle(Paint.Style.FILL);
        for (int i = 0; i < mPoints.size(); i++) {
            //輪詢切換顏色  並且每次切換時,修改對應座標點繪製顏色的下標,以達到一種動態的效果
            mPaint.setColor(colors.get((i + mRunIndex) % colors.size()));
            canvas.drawCircle(mPoints.get(i).x, mPoints.get(i).y, mCirlRadiu, mPaint);
        }
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        if (mDisposable != null && !mDisposable.isDisposed()) {
            mDisposable.dispose();
        }
    }

    public MddPmdView setRadiu(float radiu) {
        this.mRadiu = radiu;
        return MddPmdView.this;
    }

    public MddPmdView setStockWidth(float stockWidth) {
        this.mStockWidth = stockWidth;
        return MddPmdView.this;
    }

    public MddPmdView setCirlRadiu(float cirlRadiu) {
        this.mCirlRadiu = cirlRadiu;
        return MddPmdView.this;
    }

    public MddPmdView setBgColor(int bgColor) {
        this.mBgColor = bgColor;
        return MddPmdView.this;
    }

    public MddPmdView setStockColor(int stockColor) {
        this.mStockColor = stockColor;
        return MddPmdView.this;
    }

    public MddPmdView setPointCount(int count) {
        this.mPointCount = count;
        return MddPmdView.this;
    }

    public void setColors(List<Integer> colors) {
        this.colors.clear();
        if (colors != null && !colors.isEmpty()) {
            this.colors.addAll(colors);
        }
    }
}

 

下一篇:https://blog.csdn.net/qq_24179679/article/details/103646001

發佈了38 篇原創文章 · 獲贊 7 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章