最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Android自定義View實(shí)現(xiàn)圓形漸變多點(diǎn)的加載框效果

 更新時(shí)間:2025年09月14日 14:35:23   作者:夏沫瑯琊  
自定義View是Android開發(fā)中的一項(xiàng)重要技術(shù),允許開發(fā)者創(chuàng)建滿足特定需求的圖形用戶界面,這篇文章主要介紹了Android自定義View實(shí)現(xiàn)圓形漸變多點(diǎn)的加載框效果,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下

本文主要記錄創(chuàng)建一個(gè) Android 自定義加載彈窗,實(shí)現(xiàn)指定個(gè)數(shù)且從小到大的實(shí)心圓周期性旋轉(zhuǎn)的效果。

附上效果如下:

一: 自定義圓形loadingView

1.1 核心屬性定義

 //默認(rèn)參數(shù)
    private int circleCount = 8; // 圓圈數(shù)量
    private int minCircleRadius = 5; // 最小圓圈半徑
    private int maxCircleRadius = 15; // 最大圓圈半徑
    private int circleColor = Color.parseColor("#3F51B5"); //默認(rèn)顏色

這些屬性控制了加載動(dòng)畫的外觀:圓的數(shù)量、大小范圍、顏色以及動(dòng)畫實(shí)例。

1.2 構(gòu)造方法

 public CircleLoadingView(Context context) {
        super(context);
        init(null);
    }

    public CircleLoadingView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init(attrs);
    }


    public CircleLoadingView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(attrs);
    }
  • 實(shí)現(xiàn)了 3 個(gè)構(gòu)造方法,覆蓋了代碼創(chuàng)建和 XML 布局引用兩種場景
  • 所有構(gòu)造方法最終都調(diào)用 init() 方法完成初始化,符合 Android 自定義 View 的最佳實(shí)踐

1.3 初始化方法init()

  private void init(AttributeSet attrs) {
        if (attrs != null){
            TypedArray ta = getContext().obtainStyledAttributes(attrs, R.styleable.CircleLoadingView);
            circleCount = ta.getInt(R.styleable.CircleLoadingView_circleCount, circleCount);
            minCircleRadius = ta.getInt(R.styleable.CircleLoadingView_minCircleRadius, minCircleRadius);
            maxCircleRadius = ta.getInt(R.styleable.CircleLoadingView_maxCircleRadius, maxCircleRadius);
            circleColor = ta.getColor(R.styleable.CircleLoadingView_circleColor, circleColor);
            ta.recycle();
        }
        paint = new Paint();
        paint.setColor(circleColor);//畫筆顏色
        paint.setStyle(Paint.Style.FILL);//填充 繪制實(shí)心圓
        paint.setAntiAlias(true);//抗鋸齒

        initAnimation();
    }
  • 自定義屬性處理:通過 TypedArray 讀取 XML 中設(shè)置的自定義屬性(如圓的數(shù)量、顏色等),如果沒設(shè)置則使用默認(rèn)值
  • 畫筆初始化:配置繪制圓形的畫筆,設(shè)置為實(shí)心、抗鋸齒
  • 動(dòng)畫初始化:調(diào)用 initAnimation() 方法創(chuàng)建旋轉(zhuǎn)動(dòng)畫

1.4 動(dòng)畫實(shí)現(xiàn)

 // 創(chuàng)建旋轉(zhuǎn)動(dòng)畫,3秒完成一圈,無限循環(huán)
    private void initAnimation() {
        rotateAnimation = new RotateAnimation(
                0, 360,
                Animation.RELATIVE_TO_SELF, 0.5f,
                Animation.RELATIVE_TO_SELF, 0.5f
        );
        rotateAnimation.setDuration(3000);
        rotateAnimation.setRepeatCount(Animation.INFINITE);
        rotateAnimation.setInterpolator(new LinearInterpolator());
        startAnimation(rotateAnimation);
    }

1.5 繪制

這是自定義 View 的核心方法,負(fù)責(zé)繪制所有圓形:

 @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        // 獲取視圖中心坐標(biāo)
        int centerX = getWidth() / 2;
        int centerY = getHeight() / 2;
        // 計(jì)算可用的半徑(視圖最小邊的一半減去最大圓半徑)
        int availableRadius = Math.min(centerX, centerY) - maxCircleRadius;
        // 繪制每個(gè)圓
        for (int i = 0; i < circleCount; i++) {
            // 計(jì)算每個(gè)圓的角度(等分圓周,從頂部開始)
            // 減去90度(Math.PI/2)使第一個(gè)點(diǎn)位于頂部
            float angle = (float) (2 * Math.PI * i / circleCount - Math.PI / 2);
            // 計(jì)算當(dāng)前圓的半徑(從小到大漸變)
            float radius = minCircleRadius;
            if (circleCount > 1) {
                radius = minCircleRadius + (maxCircleRadius - minCircleRadius) * (float) i / (circleCount - 1);
            }
            // 計(jì)算圓的中心點(diǎn)坐標(biāo)(均勻分布在圓形軌跡上)
            float x = centerX + (float) (availableRadius * Math.cos(angle));
            float y = centerY + (float) (availableRadius * Math.sin(angle));

            // 設(shè)置畫筆顏色(可選:可以根據(jù)位置設(shè)置不同的透明度)
            paint.setAlpha(calculateAlpha(i));
            // 繪制圓
            canvas.drawCircle(x, y, radius, paint);
        }
    }

    /**
     * 根據(jù)圓點(diǎn)位置計(jì)算透明度,創(chuàng)建漸變效果
     * @param index 圓點(diǎn)索引
     * @return 透明度值(0-255)
     */
    private int calculateAlpha(int index) {
        // 可以根據(jù)需要調(diào)整透明度計(jì)算邏輯
        // 這里創(chuàng)建一個(gè)漸變效果,第一個(gè)點(diǎn)最暗,最后一個(gè)點(diǎn)較亮
        if (circleCount <= 1) return 255;
        // 計(jì)算透明度,
        return 155 + (index * 100 / (circleCount - 1));
    }

1.6: 尺寸測量

 @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        // 設(shè)置默認(rèn)大小
        int defaultSize = dp2px(80);
        int width = measureSize(defaultSize, widthMeasureSpec);
        int height = measureSize(defaultSize, heightMeasureSpec);
        setMeasuredDimension(width, height);
    }

    private int measureSize(int defaultSize, int measureSpec) {
        int result = defaultSize;
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);

        if (specMode == MeasureSpec.EXACTLY) {
            result = specSize;
        } else if (specMode == MeasureSpec.AT_MOST) {
            result = Math.min(defaultSize, specSize);
        }
        return result;
    }

    // dp轉(zhuǎn)px
    private int dp2px(float dpValue) {
        final float scale = getContext().getResources().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    }
  • 處理 View 的尺寸測量,支持 wrap_content、match_parent 和固定尺寸
  • 默認(rèn)大小為 80dp,通過 dp2px() 方法將 dp 轉(zhuǎn)為 px,適配不同屏幕密度

1.7 : attrs自定義參數(shù)

<!-- 自定義加載視圖的屬性 -->
<declare-styleable name="CircleLoadingView">
    <attr name="circleCount" format="integer" />
    <attr name="minCircleRadius" format="integer" />
    <attr name="maxCircleRadius" format="integer" />
    <attr name="circleColor" format="color" />
</declare-styleable>

目前定義了四個(gè)屬性包括圓點(diǎn)的個(gè)數(shù),顏色,最大最小的半徑. 有其他需求的我們可以繼續(xù)補(bǔ)充.

下面是完整的自定義View的代碼:

public class CircleLoadingView extends View {
    private static final String TAG = "CircleLoadingView";
    //默認(rèn)參數(shù)
    private int circleCount = 8; // 圓圈數(shù)量
    private int minCircleRadius = 5; // 最小圓圈半徑
    private int maxCircleRadius = 15; // 最大圓圈半徑
    private int circleColor = Color.parseColor("#3F51B5"); //默認(rèn)顏色
    // 旋轉(zhuǎn)動(dòng)畫
    private RotateAnimation rotateAnimation;
    // 畫筆
    private Paint paint;

    public CircleLoadingView(Context context) {
        super(context);
        init(null);
    }

    public CircleLoadingView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init(attrs);
    }


    public CircleLoadingView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(attrs);
    }


    private void init(AttributeSet attrs) {
        if (attrs != null){
            TypedArray ta = getContext().obtainStyledAttributes(attrs, R.styleable.CircleLoadingView);
            circleCount = ta.getInt(R.styleable.CircleLoadingView_circleCount, circleCount);
            minCircleRadius = ta.getInt(R.styleable.CircleLoadingView_minCircleRadius, minCircleRadius);
            maxCircleRadius = ta.getInt(R.styleable.CircleLoadingView_maxCircleRadius, maxCircleRadius);
            circleColor = ta.getColor(R.styleable.CircleLoadingView_circleColor, circleColor);
            ta.recycle();
        }
        paint = new Paint();
        paint.setColor(circleColor);//畫筆顏色
        paint.setStyle(Paint.Style.FILL);//填充 繪制實(shí)心圓
        paint.setAntiAlias(true);//抗鋸齒

        initAnimation();
    }

    // 創(chuàng)建旋轉(zhuǎn)動(dòng)畫,3秒完成一圈,無限循環(huán)
    private void initAnimation() {
        rotateAnimation = new RotateAnimation(
                0, 360,
                Animation.RELATIVE_TO_SELF, 0.5f,
                Animation.RELATIVE_TO_SELF, 0.5f
        );
        rotateAnimation.setDuration(3000);
        rotateAnimation.setRepeatCount(Animation.INFINITE);
        rotateAnimation.setInterpolator(new LinearInterpolator());
        startAnimation(rotateAnimation);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        // 獲取視圖中心坐標(biāo)
        int centerX = getWidth() / 2;
        int centerY = getHeight() / 2;
        // 計(jì)算可用的半徑(視圖最小邊的一半減去最大圓半徑)
        int availableRadius = Math.min(centerX, centerY) - maxCircleRadius;
        // 繪制每個(gè)圓
        for (int i = 0; i < circleCount; i++) {
            // 計(jì)算每個(gè)圓的角度(等分圓周,從頂部開始)
            // 減去90度(Math.PI/2)使第一個(gè)點(diǎn)位于頂部
            float angle = (float) (2 * Math.PI * i / circleCount - Math.PI / 2);
            // 計(jì)算當(dāng)前圓的半徑(從小到大漸變)
            float radius = minCircleRadius;
            if (circleCount > 1) {
                radius = minCircleRadius + (maxCircleRadius - minCircleRadius) * (float) i / (circleCount - 1);
            }
            // 計(jì)算圓的中心點(diǎn)坐標(biāo)(均勻分布在圓形軌跡上)
            float x = centerX + (float) (availableRadius * Math.cos(angle));
            float y = centerY + (float) (availableRadius * Math.sin(angle));

            // 設(shè)置畫筆顏色(可選:可以根據(jù)位置設(shè)置不同的透明度)
            paint.setAlpha(calculateAlpha(i));
            // 繪制圓
            canvas.drawCircle(x, y, radius, paint);
        }
    }

    /**
     * 根據(jù)圓點(diǎn)位置計(jì)算透明度,創(chuàng)建漸變效果
     * @param index 圓點(diǎn)索引
     * @return 透明度值(0-255)
     */
    private int calculateAlpha(int index) {
        // 可以根據(jù)需要調(diào)整透明度計(jì)算邏輯
        // 這里創(chuàng)建一個(gè)漸變效果,第一個(gè)點(diǎn)最暗,最后一個(gè)點(diǎn)較亮
        if (circleCount <= 1) return 255;
        // 計(jì)算透明度,
        return 155 + (index * 100 / (circleCount - 1));
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        // 設(shè)置默認(rèn)大小
        int defaultSize = dp2px(80);
        int width = measureSize(defaultSize, widthMeasureSpec);
        int height = measureSize(defaultSize, heightMeasureSpec);
        setMeasuredDimension(width, height);
    }

    private int measureSize(int defaultSize, int measureSpec) {
        int result = defaultSize;
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);

        if (specMode == MeasureSpec.EXACTLY) {
            result = specSize;
        } else if (specMode == MeasureSpec.AT_MOST) {
            result = Math.min(defaultSize, specSize);
        }
        return result;
    }

    // dp轉(zhuǎn)px
    private int dp2px(float dpValue) {
        final float scale = getContext().getResources().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    }

    // 開始動(dòng)畫
    public void startLoading() {
        if (rotateAnimation != null && rotateAnimation.hasEnded()) {
            startAnimation(rotateAnimation);
        }
    }

    // 停止動(dòng)畫
    public void stopLoading() {
        if (rotateAnimation != null) {
            clearAnimation();
        }
    }

    // 更新圓點(diǎn)的顏色
    public void setCircleColor(int color) {
        this.circleColor = color;
        paint.setColor(color);
        invalidate();
    }

}

二: 自定義Dialog.

2.1 代碼

這里我寫的很簡單, 直接集成DIalog. 界面也只有CircleLoadingView.

public class CircleDialog extends Dialog {
    private static final String TAG = "CircleDialog";
    private CircleLoadingView loadingView;

    public CircleDialog(@NonNull Context context) {
        super(context, R.style.LoadingDialogStyle);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_circle_dialog);
        loadingView = findViewById(R.id.loading_view);
    }

    private void initWindow() {
        Window window = getWindow();
        if (window != null) {
            // 設(shè)置窗口屬性
            WindowManager.LayoutParams params = window.getAttributes();
            // 設(shè)置窗口居中
            params.gravity = Gravity.CENTER;
            // 設(shè)置窗口寬高為包裹內(nèi)容
            params.width = WindowManager.LayoutParams.WRAP_CONTENT;
            params.height = WindowManager.LayoutParams.WRAP_CONTENT;
            // 設(shè)置窗口背景透明度
            params.dimAmount = 0.3f;
            window.setAttributes(params);

            // 設(shè)置窗口背景為透明
            window.setBackgroundDrawableResource(android.R.color.transparent);
            // 設(shè)置窗口是否有遮罩層
            window.addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
        }

        // 設(shè)置點(diǎn)擊外部是否可取消
        setCanceledOnTouchOutside(false);
    }

    // 設(shè)置加載圓圈的顏色
    public void setCircleColor(int color) {
        if (loadingView != null) {
            loadingView.setCircleColor(color);
        }
    }

    @Override
    public void show() {
        super.show();
        if (loadingView != null) {
            loadingView.startLoading();
        }
    }

    @Override
    public void dismiss() {
        super.dismiss();
        if (loadingView != null) {
            loadingView.stopLoading();
        }
    }
}

2.2: layout布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical">

    <com.test.accessbilitytest.view.CircleLoadingView
        android:layout_width="80dp"
        android:layout_height="80dp"
        android:id="@+id/loading_view"
        android:layout_gravity="center_horizontal"
        app:circleCount="8"
        app:minCircleRadius="10"
        app:maxCircleRadius="16"
        app:circleColor="#fffdbe32"
        />
</LinearLayout>

2.3: dialog的樣式

<!-- 加載彈窗樣式 -->
<style name="LoadingDialogStyle" parent="@android:style/Theme.Dialog">
    <!-- 不顯示標(biāo)題欄 -->
    <item name="android:windowNoTitle">true</item>
    <!-- 背景透明 -->
    <item name="android:windowBackground">@android:color/transparent</item>
    <!-- 窗口進(jìn)入退出動(dòng)畫 -->
    <item name="android:windowAnimationStyle">@android:style/Animation.Dialog</item>
</style>

三: 彈框的特點(diǎn).

    1.	核心是CircleLoadingView自定義視圖,它負(fù)責(zé)繪制 8個(gè)從小到大的實(shí)心圓,并通過旋轉(zhuǎn)動(dòng)畫實(shí)現(xiàn)周期性旋轉(zhuǎn)效果。
    2.	通過自定義屬性,您可以輕松調(diào)整:
       		圓的數(shù)量(默認(rèn) 8個(gè))
       		最小圓半徑
       		最大圓半徑
       		圓的顏色
    3.	LoadingDialog封裝了彈窗的顯示邏輯,包括設(shè)置彈窗樣式、背景透明度等。
    4.	使用方法簡單:
       創(chuàng)建LoadingDialog實(shí)例
       調(diào)用show()方法顯示
       調(diào)用dismiss()方法隱藏

總結(jié) 

到此這篇關(guān)于Android自定義View實(shí)現(xiàn)圓形漸變多點(diǎn)的加載框效果的文章就介紹到這了,更多相關(guān)Android自定義加載彈窗內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論

托克逊县| 房山区| 鸡西市| 西乌珠穆沁旗| 阿克陶县| 华蓥市| 珲春市| 宾阳县| 双桥区| 商南县| 西峡县| 廉江市| 秦皇岛市| 沙河市| 射洪县| 扬州市| 南郑县| 慈溪市| 红安县| 米林县| 绥芬河市| 巩义市| 余姚市| 华蓥市| 通化市| 青川县| 冀州市| 桃江县| 吉木乃县| 祥云县| 连州市| 楚雄市| 霍城县| 仁寿县| 金川县| 合川市| 顺义区| 岐山县| 甘泉县| 梅州市| 宿州市|