1. 程式人生 > >Android 兩種方式實現類似水波擴散效果

Android 兩種方式實現類似水波擴散效果

amp round ini 視覺差 arr arraylist inf nim you

技術分享圖片
兩種方式實現類似水波擴散效果,先上圖為敬

  1. 自定義view實現
  2. 動畫實現

技術分享圖片

### 自定義view實現

思路分析:通過canvas畫圓,每次改變圓半徑和透明度,當半徑達到一定程度,再次從中心開始繪圓,達到不同層級的效果,通過不斷繪制達到view擴散效果

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 = 33;//擴散延遲間隔,越大擴散越慢
private List<Integer> spreadRadius = new ArrayList<>();//擴散圓層級數,元素為擴散的距離
private List<Integer> alphas = new ArrayList<>();//對應每層圓的透明度

style文件裏自定義屬性

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

初始化


public SpreadView(Context context) {
    this(context, null, 0);
}

public SpreadView(Context context, @Nullable AttributeSet attrs) {
    this(context, attrs, 0);
}

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

    centerPaint = new Paint();
    centerPaint.setColor(centerColor);
    centerPaint.setAntiAlias(true);
    //最開始不透明且擴散距離為0
    alphas.add(255);
    spreadRadius.add(0);
    spreadPaint = new Paint();
    spreadPaint.setAntiAlias(true);
    spreadPaint.setAlpha(255);
    spreadPaint.setColor(spreadColor);
}

確定圓心位置

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);
    //圓心位置
    centerX = w / 2;
    centerY = h / 2;
}

自定義view的繪制


@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    for (int i = 0; i < spreadRadius.size(); i++) {
        int alpha = alphas.get(i);
        spreadPaint.setAlpha(alpha);
        int width = spreadRadius.get(i);
        //繪制擴散的圓
        canvas.drawCircle(centerX, centerY, radius + width, spreadPaint);

        //每次擴散圓半徑遞增,圓透明度遞減
        if (alpha > 0 && width < 300) {
            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);
    }
    //超過8個擴散圓,刪除最先繪制的圓,即最外層的圓
    if (spreadRadius.size() >= 8) {
        alphas.remove(0);
        spreadRadius.remove(0);
    }
    //中間的圓
    canvas.drawCircle(centerX, centerY, radius, centerPaint);
    //TODO 可以在中間圓繪制文字或者圖片

    //延遲更新,達到擴散視覺差效果
    postInvalidateDelayed(delayMilliseconds);
}

xml樣式

<com.airsaid.diffuseview.widget.SpreadView
    android:id="@+id/spreadView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:spread_center_color="@color/colorAccent"
    app:spread_delay_milliseconds="35"
    app:spread_distance="5"
    app:spread_max_radius="90"
    app:spread_radius="100"
    app:spread_spread_color="@color/colorAccent" />

效果圖
技術分享圖片

中心圓處可以自定義寫文字,畫圖片等等...

動畫實現

思路分析:通過動畫實現,imageView不停做動畫縮放+漸變
最中心的imageView保持不變
中間一層imageView從原始放大到1.4倍,同時從不透明變為半透明
最外層的imageView從1.4倍放大到1.8倍,同時從半透明變為全透明
利用shape畫一個圓,作為動畫基礎視圖

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <corners android:radius="65dp"/>
    <solid android:color="@color/colorAccent"/>
</shape>

布局視圖

<FrameLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <!--中心imageView-->
    <ImageView
        android:id="@+id/iv_wave"
        android:layout_width="130dp"
        android:layout_height="130dp"
        android:layout_gravity="center"
        android:background="@drawable/shape_circle" />
    <!--中間的imageView-->
    <ImageView
        android:id="@+id/iv_wave_1"
        android:layout_width="130dp"
        android:layout_height="130dp"
        android:layout_gravity="center"
        android:background="@drawable/shape_circle" />
    <!--最外層imageView-->
    <ImageView
        android:id="@+id/iv_wave_2"
        android:layout_width="130dp"
        android:layout_height="130dp"
        android:layout_gravity="center"
        android:background="@drawable/shape_circle" />
</FrameLayout>

中間imageView的動畫

private void setAnim1() {
    AnimationSet as = new AnimationSet(true);
    //縮放動畫,以中心從原始放大到1.4倍
    ScaleAnimation scaleAnimation = new ScaleAnimation(1.0f, 1.4f, 1.0f, 1.4f,
            ScaleAnimation.RELATIVE_TO_SELF, 0.5f,
            ScaleAnimation.RELATIVE_TO_SELF, 0.5f);
    //漸變動畫
    AlphaAnimation alphaAnimation = new AlphaAnimation(1.0f, 0.5f);
    scaleAnimation.setDuration(800);
    scaleAnimation.setRepeatCount(Animation.INFINITE);
    alphaAnimation.setRepeatCount(Animation.INFINITE);
    as.setDuration(800);
    as.addAnimation(scaleAnimation);
    as.addAnimation(alphaAnimation);
    iv1.startAnimation(as);
}

最外層imageView的動畫

private void setAnim2() {
    AnimationSet as = new AnimationSet(true);
    //縮放動畫,以中心從1.4倍放大到1.8倍
    ScaleAnimation scaleAnimation = new ScaleAnimation(1.4f, 1.8f, 1.4f, 1.8f,
            ScaleAnimation.RELATIVE_TO_SELF, 0.5f,
            ScaleAnimation.RELATIVE_TO_SELF, 0.5f);
    //漸變動畫
    AlphaAnimation alphaAnimation = new AlphaAnimation(0.5f, 0.1f);
    scaleAnimation.setDuration(800);
    scaleAnimation.setRepeatCount(Animation.INFINITE);
    alphaAnimation.setRepeatCount(Animation.INFINITE);
    as.setDuration(800);
    as.addAnimation(scaleAnimation);
    as.addAnimation(alphaAnimation);
    iv2.startAnimation(as);
}

效果圖
技術分享圖片

相比較而言,自定義view的效果更好點,動畫實現起來更方便點。

兩種方式實現的擴散效果介紹完畢,具體項目裏還是要按需變動的。

同時歡迎關註哈

Android 兩種方式實現類似水波擴散效果