两种方式实现类似水波扩散效果,先上图为敬

  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的效果更好点,动画实现起来更方便点。

两种方式实现的扩散效果介绍完毕,具体项目里还是要按需变动的。

发布评论

分享到:

IT虾米网

微信公众号号:IT虾米 (左侧二维码扫一扫)欢迎添加!

AndroidManifest 配置主活动详解
你是第一个吃螃蟹的人
发表评论

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。