Android 两种方式实现类似水波扩散效果

原文链接 https://mp.weixin.qq.com/s/M19tp_ShOO6esKdozi7Nlg

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

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

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

欢迎关注我的博客:https://blog.manjiexiang.cn/

同时欢迎关注微信公众号

原文地址:https://www.cnblogs.com/taixiang/p/9095464.html

时间: 2024-07-29 18:53:42

Android 两种方式实现类似水波扩散效果的相关文章

两种方式实现类似qq搜索的切换

qq的搜索功能在点击搜索框时整个页面上移,出现透明布局.该效果是模仿iOS实现的,但是在Android也是很容易实现的.于是就花了点时间仿照效果写了一个demo.可能实现方式并不是完全相同. 具体请看效果图: 详细说明略.第一种是利用隐藏的透明LinearLayout实现效果.第二.三种是通过PopupWindow实现的,只有一处区别,即搜索框的两种状态.第二种采用的是ListView的addHeaderView实现的. 不多说直接上代码 第一种 /***********************

Android 两种方式播放视频

主MainActivity的布局配置文件 这是activity_main.xml.主要出现两个按钮,按钮一通过mediaplayer播放,按钮二通过videoview播放 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"     xmlns:tools="http://schemas.android.com/tools"     android:layout_wid

[Android] Android ViewPager 中加载 Fragment的两种方式 方式(二)

接上文: https://www.cnblogs.com/wukong1688/p/10693338.html Android ViewPager 中加载 Fragmenet的两种方式 方式(一) 二.使用Fragment来填充ViewPager Google 官方是建议我们使用Fragment来填充ViewPager的,这样可以更加方便的生成每个Page以及管理 每个Page的生命周期!当然它给我们提供了两个不同的Adapter,他们分别是: FragmentPageAdapter和Fragm

Android实战简易教程-第四十九枪(两种方式实现网络图片异步加载)

加载图片属于比较耗时的工作,我们需要异步进行加载,异步加载有两种方式:1.通过AsyncTask类进行:2.通过Handler来实现,下面我们就来看一下如何通过这两种方式实现网络图片的异步加载. 一.AsyncTask方式 1.main.xml: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.co

Android提交数据到服务器的两种方式四种方法

Android应用开发中,会经常要提交数据到服务器和从服务器得到数据,本文主要是给出了利用http协议采用HttpClient方式向服务器提交数据的方法. /** * @author Dylan * 本类封装了Android中向web服务器提交数据的两种方式四种方法 */ public class SubmitDataByHttpClientAndOrdinaryWay { /** * 使用get请求以普通方式提交数据 * @param map 传递进来的数据,以map的形式进行了封装 * @p

Android解析XML文档的两种方式的简单对比

Android之所以会用到解析XML文档,不仅与JAVA对XML的解析比较简单,而且还因为XML是Android在网络间传递信息的主要存储方式.下面我简单谈谈Android对XML文档解析的两种方式:dom和sax.dom解析方式是,解析方法将一个XML文件看成是一棵树.由数据结构的知识我们知道对树的处理比较简单,就是对树的节点进行增,删,改,查,这也是dom的一个最大优点.但是,dom方式在解析的时候是一次性就将整个XML文档读进内存,这坏处不用我说了吧,我宝贵的内存是禁不起这么折腾的. sa

Android模拟点击的两种方式

导论 在Android中模拟一个点击事件有两种方式是通过模拟MotionEvent来实现:一种是通过ADB来实现 第一种:模拟MotionEvent 通用方法如下: private void setSimulateClick(View view, float x, float y) { long downTime = SystemClock.uptimeMillis(); final MotionEvent downEvent = MotionEvent.obtain(downTime, dow

Android开发之使用sqlite3工具操作数据库的两种方式

使用 sqlite3 工具操作数据库的两种方式 请尊重他人的劳动成果,转载请注明出处:Android开发之使用sqlite3工具操作数据库的两种方式 http://blog.csdn.net/fengyuzhengfan/article/details/40193123 在Android SDK的tools目录下提供了一"sqlite3.exe工具,它是一个简单的SQLite数据库管理工具,类似于MySQL提供的命令行窗口在有些时候,开发者利用该工具来査询. 管理数据库. 下面介绍两种方式: 第

【转】android创建Popwindow弹出菜单的两种方式

方法一的Activity [java] view plaincopy package com.app.test02; import android.app.Activity; import android.os.Bundle; import android.view.Gravity; import android.view.MotionEvent; import android.view.View; import android.view.View.OnClickListener; import