首頁 > 軟體

Android自定義View實現水波紋擴散效果

2022-08-30 14:03:21

效果:水波紋擴散

場景:雷達、按鈕點選效果、搜尋等

實現:先上效果圖,之前記得支付寶有一個咻一咻,當時就是水波紋效果,實現起來一共兩步,第一畫內圓,第二畫多個外圓,不同時建立有間隔建立然後緩慢增大外圓半徑,到達最遠距離時移除掉,擴散時把透明度從255-1不斷賦值即可。複雜在第二步,開工。

開工

1、建立RippleView.class, 繼承與View

RippleView主要初始化一些資料,

onSizeChanged主要獲取位置座標

onDraw主要繪製影象,關鍵

public class RippleView extends View {
 
    public RippleView(Context context) {
        this(context, null);
    }
 
    public RippleView(Context context, @Nullable AttributeSet attrs) {
        //this(context, null, 0);//如果第二個引數寫null,則自定義屬性將不可用
        this(context, attrs, 0);
    }
  
    public RippleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        ........
    }    <br>  
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        ........
    }
 
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
 
        ........
    }
}       

1.1特殊屬性解釋 

alpha陣列:目的是讓每個外圓(擴散圓)透明度從不透明到透明(255-1)

spreadRadius:擴散圓的半徑是遞增的

private Paint centerPaint; //中心圓paint
private int radius = 100; //中心圓半徑
private Paint spreadPaint; //擴散圓paint
private float centerX;//圓心x
private float centerY;//圓心y
private int distance = 5; //每次圓遞增間距
private int maxRadius = 80; //最大圓半徑
private int delayMilliseconds = 30;//擴散延遲間隔,越大擴散越慢
private List<Integer> spreadRadius = new ArrayList<>();//擴散圓層級數,元素為擴散的距離
private List<Integer> alphas = new ArrayList<>();//對應每層圓的透明度 

1.2新建attrs.xml檔案(res/values)

我們需要在xml中使用自定義屬性來控制初始值,如內圓半徑,擴散顏色,內圓顏色等

<resources>
 
  <declare-styleable name="SpreadView">
    <!--中心圓顏色-->
    <attr name="spread_center_color" format="color" />
    <!--中心圓半徑-->
    <attr name="spread_radius" format="integer" />
    <!--擴散圓顏色-->
    <attr name="spread_spread_color" format="color" />
    <!--擴散間距-->
    <attr name="spread_distance" format="integer" />
    <!--擴散最大半徑-->
    <attr name="spread_max_radius" format="integer" />
    <!--擴散延遲間隔-->
    <attr name="spread_delay_milliseconds" format="integer" />
  </declare-styleable>
 
</resources>

在RippleView中拿到值

public RippleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
       super(context, attrs, defStyleAttr);
       TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.SpreadView, defStyleAttr, 0);
       radius = typedArray.getInt(R.styleable.SpreadView_spread_radius, radius);
       maxRadius = typedArray.getInt(R.styleable.SpreadView_spread_max_radius, maxRadius);
       int centerColor = typedArray.getColor(R.styleable.SpreadView_spread_center_color,
               ContextCompat.getColor(context, android.R.color.holo_red_light));
       int spreadColor = typedArray.getColor(R.styleable.SpreadView_spread_spread_color,
               ContextCompat.getColor(context, R.color.color_F71816));
       distance = typedArray.getInt(R.styleable.SpreadView_spread_distance, distance);
       typedArray.recycle();
 
   }

context.obtainStyledAttributes可以獲取我們在xml檔案的屬性值,最後typedArray.recycle();釋放掉,為什麼釋放掉這也是一個學問,自行百度。

centerColor為內圓顏色,

spreadColor擴散顏色

1.3初始化畫筆

public RippleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        
        .....
 
        //中心圓
        centerPaint = new Paint();
        centerPaint.setColor(centerColor);<br>     //消除鋸齒
        centerPaint.setAntiAlias(true);
 
        //水波紋擴散
        spreadPaint = new Paint();
        spreadPaint.setColor(spreadColor);
        spreadPaint.setAntiAlias(true);<br>     //填充和描邊,上面2張圖片效果不同取決於該屬性
        spreadPaint.setStyle(Paint.Style.STROKE);
        spreadPaint.setAlpha(255);
        //初始化第一個水波紋,擴散半徑為0,透明度為255(不透明)
        spreadRadius.add(0);
        alphas.add(255);
    } /**在控制元件大小發生改變時呼叫。所以這裡初始化會被呼叫一次*/<br>@Override<br>protected void onSizeChanged(int w, int h, int oldw, int oldh) {<br>      super.onSizeChanged(w, h, oldw, oldh);<br>      //圓心位置<br>      centerX = w / 2;<br>      centerY = h / 2;<br>  }

2、開始繪製onDraw()

我們已經做了好前奏,剩下的就開始繪製了,首先我們要確定幾個圓才能形成水波紋效果,1,2還是3,不確定那就先從一個開始,spreadRadius我們在建立畫筆時已經新增了一個圓,那我們就遍歷spreadRadius陣列,透明度alphas[i]把值遞減(255-1),spreadRadius[i]圓半徑遞增,圓數量超過8個就移除第1個,如果最外圓擴散半徑達到最大半徑時新增新擴散圓。最後通過postInvalidateDelayed(30),延遲重新整理來達到擴散的樣式。

@Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
 
        for (int i = 0; i < spreadRadius.size(); i++) {
            //透明度
            int alpha = alphas.get(i);
            //半徑
            int width = spreadRadius.get(i);
            spreadPaint.setAlpha(alpha);
            //繪製擴散的圓
            canvas.drawCircle(centerX, centerY, radius + width, spreadPaint);
            if (alpha > 0 && width < 255) {
                //遞減
                alpha = (alpha - distance) > 0 ? (alpha - distance) : 1;
                alphas.set(i, alpha);
                //遞增
                spreadRadius.set(i, width + distance);
            }
        }
        if (spreadRadius.get(spreadRadius.size() - 1) > maxRadius) {
            spreadRadius.add(0);
            alphas.add(255);
        }
        if (spreadRadius.size() > 8) {
            spreadRadius.remove(0);
            alphas.remove(0);
        }
        //中間的圓
        canvas.drawCircle(centerX, centerY, radius, centerPaint);
        //延遲更新,達到擴散視覺差效果
        postInvalidateDelayed(delayMilliseconds);
    }

到此這篇關於Android自定義View實現水波紋擴散效果的文章就介紹到這了,更多相關Android水波紋擴散內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com