Android 水波纹特效

Android水纹波浪动画 总体思路如下: 1、将波浪效果绘制成一个静态的图片 2、将图片往水平和竖直方向,同时并按一定的速率移动 在实现的过程中,主要利用正弦函数 y=Asin(ωx+φ)+h ,设置四个参数(振幅、高度、波长和偏移)来实现波浪的动画效果。 阅读详情

先看一下动画效果:第一次上传gif图片 先录的mp4视频 后来转的gif
这里写图片描述
Android动画在这里就不详细讲了,网上一大把,不清楚的可以去看看。这里只讲这个动画的视线逻辑。
这个动画这里分四个部分:
1.最底部图片心跳动画
2.水波纹扩散动画
3.头像出现的时机动画
4.中间个人头像动画

在这里先讲第一部分:最底部图片心跳动画

 int size = mList.length;
        animPoints = new Animation[size];
        /**
         * 五个小点 动画显示
         * */
        for (int i = 0; i < size; i++) {
            final int j = i;
            LayoutParams mSmallCircleParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
            if (j == 0) {
                mSmallCircleParams.rightMargin = ResUtil.getDimens(mContext, R.dimen.common_padding_140);
                mSmallCircleParams.gravity = Gravity.RIGHT;
                mSmallCircleParams.topMargin = ResUtil.getDimens(mContext, R.dimen.common_padding_380);
            } else if (j == 1) {
                mSmallCircleParams.rightMargin = ResUtil.getDimens(mContext, R.dimen.common_padding_75);
                mSmallCircleParams.gravity = Gravity.RIGHT;
                mSmallCircleParams.topMargin = ResUtil.getDimens(mContext, R.dimen.common_padding_89);
            } else if (j == 2) {
                mSmallCircleParams.leftMargin = ResUtil.getDimens(mContext, R.dimen.common_padding_17);
                mSmallCircleParams.topMargin = ResUtil.getDimens(mContext, R.dimen.common_padding_150);
            } else if (j == 3) {
                mSmallCircleParams.leftMargin = ResUtil.getDimens(mContext, R.dimen.common_padding_39);
                mSmallCircleParams.topMargin = ResUtil.getDimens(mContext, R.dimen.common_padding_240);
            } else if (j == 4) {
                mSmallCircleParams.rightMargin = ResUtil.getDimens(mContext, R.dimen.common_padding_112);
                mSmallCircleParams.gravity = Gravity.RIGHT;
                mSmallCircleParams.topMargin = ResUtil.getDimens(mContext, R.dimen.common_padding_224);
            }

            ImageView mSmallCircleView = new ImageView(getContext());
            mSmallCircleView.setImageResource(mList[j]);
            addView(mSmallCircleView, mSmallCircleParams);

            /**加载动画*/
            animPoints[j] = AnimationUtils.loadAnimation(getContext(), R.anim.anim_the_heartbeat);
            mSmallCircleView.startAnimation(animPoints[j]);

            animPoints[j].setAnimationListener(new Animation.AnimationListener() {
                @Override
                public void onAnimationStart(Animation animation) {
                    if (mAnimationProgressListener != null) {
                        mAnimationProgressListener.startAnimation();
                    }
                }

                @Override
                public void onAnimationEnd(Animation animation) {
                    if (mAnimationProgressListener != null) {
                        mAnimationProgressListener.endAnimation();
                    }

                    if (null != animPoints && null != animPoints[j]) {
                        animPoints[j].cancel();
                    }

                }

                @Override
                public void onAnimationRepeat(Animation animation) {

                }
            });

        }

在这里先讲第二部分:水波纹扩散动画

 //布局 管理器,让圆剧中显示
        LayoutParams rippleParams = new LayoutParams((int) (2 * (rippleRadius + rippleStrokeWidth * 3)), (int) (2 * (rippleRadius + rippleStrokeWidth * 3)));
        rippleParams.gravity = Gravity.CENTER;

        //动画的集合
        ArrayList<Animator> animatorList = new ArrayList<>();

        //水波纹 缩放、渐变动画
        for (int i = 0; i < rippleAmount; i++) {

            RipplView rippleView = new RipplView(getContext());
            addView(rippleView, rippleParams);
            rippleViewList.add(rippleView);

            //伸缩动画
            float rippleScale = 6.0f;
            final ObjectAnimator scaleXAnimator = ObjectAnimator.ofFloat(rippleView, "ScaleX", 1.0f, rippleScale);
            scaleXAnimator.setRepeatCount(ValueAnimator.INFINITE);
            scaleXAnimator.setRepeatMode(ObjectAnimator.RESTART);
            scaleXAnimator.setStartDelay(i * rippleDelay);
            animatorList.add(scaleXAnimator);

            final ObjectAnimator scaleYAnimator = ObjectAnimator.ofFloat(rippleView, "ScaleY", 1.0f, rippleScale);
            scaleYAnimator.setRepeatCount(ValueAnimator.INFINITE);
            scaleYAnimator.setRepeatMode(ObjectAnimator.RESTART);
            scaleYAnimator.setStartDelay(i * rippleDelay);
            animatorList.add(scaleYAnimator);

            //透明度动画
            final ObjectAnimator alphaAnimator = ObjectAnimator.ofFloat(rippleView, "Alpha", 1.0f, 0f);
            alphaAnimator.setRepeatCount(ValueAnimator.INFINITE);
            alphaAnimator.setRepeatMode(ObjectAnimator.RESTART);
            alphaAnimator.setStartDelay(i * rippleDelay);
            animatorList.add(alphaAnimator);
        }

        //开始动画
        animatorSet.playTogether(animatorList);
        //动画的监听
        animatorSet.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animator) {
                if (mAnimationProgressListener != null) {
                    mAnimationProgressListener.startAnimation();
                }
            }

            @Override
            public void onAnimationEnd(Animator animator) {
                if (mAnimationProgressListener != null) {
                    mAnimationProgressListener.endAnimation();
                }
            }

            @Override
            public void onAnimationCancel(Animator animator) {

            }

            @Override
            public void onAnimationRepeat(Animator animator) {

            }
        });

在这里讲第三部分:头像出现的时机动画
简单的理解就是划分了六个区域:

private final static int showNum = 5;
    private static long delayMillis = 4000;

    private int radiusP;
    private int radiusC;
    private int radiusB;
    private int pointCX;
    private int pointCY;
    private int page = 0;
    private int lastNum = 0;
    private boolean isAddShowing = false;
    private List<String> mGodHeadPhoto = new ArrayList<>();
    private Handler mHandler = new Handler();
    private UserRunnable userRunnable;
    private CircleImageView[] imageViews;
    private ObjectAnimator[] animator;

    /**
     * 设置大神头像
     */
    public void setUserPhoto(List<String> godHeadPhoto) {
        Log.e(TAG, "setUserPhoto==11==" + (null == godHeadPhoto ? 0 : godHeadPhoto.size()));
        if (null == godHeadPhoto || godHeadPhoto.isEmpty()) {
            return;
        }
        mGodHeadPhoto.addAll(godHeadPhoto);
        Log.e(TAG, "setUserPhoto==22==" + mGodHeadPhoto.size() + "==isAddShowing==" + isAddShowing);
        if (isAddShowing) {
            return;
        }
        page = 0;
        lastNum = 0;
        isAddShowing = true;
        if (radiusP <= 0 || radiusC <= 0 || radiusB <= 0 || pointCX <= 0 || pointCY <= 0) {
            this.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
                @Override
                public boolean onPreDraw() {
                    RippleView.this.getViewTreeObserver().removeOnPreDrawListener(this);
                    //RippleView宽
                    int rippleW = RippleView.this.getWidth();
                    //RippleView高
                    int rippleH = RippleView.this.getHeight();
                    radiusP = ResUtil.getDimens(mContext, R.dimen.common_padding_16);
                    radiusC = ResUtil.getDimens(mContext, R.dimen.common_padding_36);
                    int padding = ResUtil.getDimens(mContext, R.dimen.common_padding_20);
                    radiusB = rippleW / 2 - radiusP - padding;
                    pointCX = rippleW / 2;
                    pointCY = rippleH / 2;

                    startShowUserList(true);
                    return true;
                }
            });
        } else {
            startShowUserList(true);
        }
    }

    /**
     * 开始显示
     *
     * @param isFirst 是否第一次显示
     */
    private void startShowUserList(boolean isFirst) {
        if (isHidden || (!isFirst && isAddShowing)) {
            return;
        }
        isAddShowing = true;
        showNextUserList();
    }

    /**
     * 获得当前显示大神list
     *
     * @return
     */
    private List<String> getCurShowList() {
        if (null == mGodHeadPhoto || mGodHeadPhoto.isEmpty()) {
            return null;
        }
        int size = mGodHeadPhoto.size();
        if (showNum >= size) {
            page = 0;
            lastNum = size;
            return mGodHeadPhoto;
        }
        int start = lastNum + page * showNum;
        if (start >= size) {
            return null;
        }
        int end = lastNum + (page + 1) * showNum;
        if (end >= size) {
            //列表已经展示结束
            page = 0;
            if (end == size) {
                lastNum = 0;
                return mGodHeadPhoto.subList(start, size);
            } else {
                lastNum = end - size;
                List<String> list = new ArrayList<>();
                list.addAll(mGodHeadPhoto.subList(start, size));
                list.addAll(mGodHeadPhoto.subList(0, lastNum));
                return list;
            }
        } else {
            page++;
            return mGodHeadPhoto.subList(start, end);
        }
    }

    /**
     * @param radiusP 五个随机大神头像半径
     * @param radiusC 中心点圆半径
     * @param radiusB 显示区域半径
     * @param pointCX 中心点x坐标
     * @param pointCY 中心点y坐标
     */
    private void addViewPhoto(int radiusP, int radiusC, int radiusB, int pointCX, int pointCY, List<String> list) {
        Log.e(TAG, "addViewPhoto==" + (null == list ? 0 : list.size()) + "==lastNum==" + lastNum + "==page==" + page + "==mGodHeadPhoto.size==" + mGodHeadPhoto.size());
        if (null != imageViews) {
            for (int i = 0; i < imageViews.length; i++) {
                if (null != imageViews[i]) {
                    RippleView.this.removeView(imageViews[i]);
                }
            }
        }
        if (userRunnable != null) {
            mHandler.removeCallbacks(userRunnable);
        }
        int size = null == list ? 0 : list.size();
        if (size == 0) {
            isAddShowing = false;
            animPhotos = null;
            imageViews = null;
            return;
        }
        animPhotos = new Animation[size];
        imageViews = new CircleImageView[size];
        animator = new ObjectAnimator[size];

        //动画控件的宽高
        for (int i = 0; i < size; i++) {
            final int k = i;
            int x1;
            int y1;
            int x2;
            int y2;
            if (k == 0) {
                /**随机按钮分四片区域显示
                 * 左上角区域
                 */
                x1 = pointCX - radiusB;
                y1 = pointCY - radiusB;

                x2 = pointCX - radiusP;
                y2 = pointCY - radiusC - radiusP;
            } else if (k == 1) {
                /**随机按钮分四片区域显示
                 * 右上角区域
                 */
                x1 = pointCX + radiusP;
                y1 = pointCY - radiusB;

                x2 = pointCX + radiusB;
                y2 = pointCY - radiusC;
            } else if (k == 2) {
                /**随机按钮分四片区域显示
                 * 左下角区域
                 */
                x1 = pointCX - radiusB;
                y1 = pointCY + radiusC + radiusP;

                x2 = pointCX - radiusP;
                y2 = pointCY + radiusB;
            } else if (k == 3) {
                /**随机按钮分四片区域显示
                 * 右下角区域
                 */
                x1 = pointCX + radiusP;
                y1 = pointCY + radiusC + radiusP;

                x2 = pointCX + radiusB;
                y2 = pointCY + radiusB;
            } else {
                int yshu = getRandomInt(Integer.MAX_VALUE) % 2;
                if (yshu == 0) {
                    /**随机按钮分四片区域显示
                     * 左中区域
                     */
                    x1 = pointCX - radiusB;
                    y1 = pointCY - radiusC + radiusP;

                    x2 = pointCX - radiusC - radiusP;
                    y2 = pointCY + radiusC - radiusP;
                } else {
                    /**随机按钮分四片区域显示 j
                     * 右中区域
                     */
                    x1 = pointCX + radiusC + radiusP;
                    y1 = pointCY - radiusC + radiusP;

                    x2 = pointCX + radiusB;
                    y2 = pointCY + radiusC - radiusP;
                }
            }
//            Log.e("addView", "addView x ==== == " + ((x2 - x1) / 2 + x1));
//            Log.e("addView", "addView y ==== == " + ((y2 - y1) / 2 + y1));
            //随机生成一个屏内的位置来显示动画

            int xs = 0;
            int ys = 0;
            boolean flag = true;
            while (flag) {
                xs = getRandomInt(Integer.MAX_VALUE) % (x2 - x1) + x1;
                ys = getRandomInt(Integer.MAX_VALUE) % (y2 - y1) + y1;
                if (isCricle(xs, ys)) {
                    flag = false;
                }
            }

            final int x = xs;
            final int y = ys;
            final String pathPhoto = list.get(k);

//            Log.e("addView", "addView x   === " + x);
//            Log.e("addView", "addView y   === " + y);
            mHandler.postDelayed(new WaitPhotoRunnable(pathPhoto, k, x, y), k * 180);

        }
        showNextUserList();
    }

deom下载地址

Android水波纹效果实现与实战应用 水波纹效果是一种视觉上的动画效果,它模仿了液体表面在受到干扰时产生的波纹扩散。在Android平台上,这一效果被广泛应用于用户交互界面,提供了更为生动、富有层次的视觉体验。随着Android版本的不断更新,水波纹效果的实现方式也在不断进化,从最初的简单图片处理到现在的硬件加速和Shader编程,极大地提升了用户体验。自定义View在Android开发中是实现个性化UI界面的强大工具。 阅读详情

相关推荐

Android 5.0水波纹特效实现与自定义RippleEffect实战

Android 5.0(Lollipop)的发布标志着Material Design设计语言在移动平台上的全面落地,其中最引人注目的交互细节之一便是“水波纹”(Ripple Effect)反馈动画。该效果通过模拟真实世界中水滴落入水面时扩散的动态视觉,增强了用户操作的可感知性与界面的响应感。系统默认的水波纹颜色由?控制,通常为半透明黑色(#1F000000)或白色(暗主题下)。开发者可在主题中重写该值以匹配品牌色。</style>-- 半透明蓝色 -->

weixin_35749545的博客 879

Android 那些事– 小米手环 测量心率 动画实现

Android 那些事– 小米手环 测量心率 动画实现双11的时候,买了一枚小米手环2,据说有测量心率的功能,如下图:觉得这个心跳图挺好玩,然后琢磨琢磨实现了一下,先上效果图: 第一步:分解动画整体分为两个部分:圆环转动和心跳图。最外面那一层就是一个带缺口的圆环加一张图片,这个不是动画,嵌一个背景就行;里面一层是有动画的圆环,最里面一层是心跳图动画,那么还原主要也就是圆环动画和心率图动画两个部分。

xueerfei的专栏 1万+

从412到200:一步步拆解瑞数6代jsvmp的cookie生成与验证流程

本文深入解析瑞数6代JSVMP的动态安全防护机制,详细拆解从412到200状态的cookie生成与验证流程。通过剖析JSVMP虚拟机核心机制、动态元数据解析及环境检测绕过策略,为逆向工程师提供实用的技术解决方案,帮助突破瑞数6代的高级防御体系。

weixin_30342209的博客 508

Android实现水波纹控件的方法

Path可以绘制二次曲线或者三次曲线到画布上,moveTo()方法将path移动到手机屏幕的(-2*waveLength,distanceY)这个点,然后以这个点为起始点绘制二次曲线曲线,rQuadTo(),以最后点为相对位置点进行取点绘制。在属性动画里面,不断改变起始点的位置,这样绘制的水波纹就会平移。如果rect的宽度无限小,那么获取的矩形区域会近似为一个点,这个点就是图片移动的y坐标。有很多app使用过水波纹的这样的效果,看着很酷酷的样子,所以自己就撸码写了一个。自定义view绘制水波纹控件。...

wuxiaopengnihao1的博客 525

阿里云百炼接入本地Claude,接入idea

阿里云百炼平台提供两种接入方式:未购买套餐时使用通用API Key(sk-xxxxx),需注意免费额度独立计算且不会自动切换模型;购买Coding Plan套餐后使用专属API Key(sk-sp-xxxxx),享受固定月费无超支风险。配置需在.claude/settings.json中设置认证信息,包括API Key和Base URL。建议开启"用完即停"功能避免意外扣费,不同模型的免费额度互不影响。购买套餐后还可通过IDEA插件Claude Code进行集成,实现固定费用下的稳定使用

fengtangjiang的博客 1363

银河麒麟V10ServerSP3中安装Nacos2.4.x详细教程

银河麒麟V10ServerSP3中安装Nacos2.4.x详细教程

yuanjinshenglife的专栏 1303

Android圆形水波纹按钮的实现(Ripple)

在Android中,谷歌已经提供了对于按钮水波纹效果的一个实现。在组件的中添加以下代码即可实现:超出组件边框(但不超出父类视图),此时水波纹效果为圆形:android:background="?android:attr/selectableItemBackgroundBorderless"不超出组件边框,水波纹效果为组件的形状:android:background="?android:attr/s...

ZGUIZ的博客 1万+

BERTopic模型入门教程(附代码+参数调节)

BERTopic 是一种用于从文本数据中提取主题模型的新型方法。通过结合 BERT嵌入和传统的主题模型来生成语义丰富的主题。传统的主题模型(如LDA)主要依赖于词频矩阵,而 BERTopic 通过预训练语言模型生成高维语义嵌入来捕捉词语间的复杂关系,因此可以更好地处理上下文信息。BERTopic模型可以看作是创建其主题表示的一系列步骤。核心原理如下:就本质而言,BERTopic就是一个拼装框架,可以把每部分都替换成其他模型,只要完成任务即可。

m0_52069102的博客 1万+

Android特效专辑(一)——水波纹过渡特效(首页)

Android特效专辑(一)——水波纹过渡特效(APP欢迎页)也是今天看到的一个特效,感觉挺漂亮的,最近也一直在筹划一个APP,就想把他当做APP的首页,然后加些处理,关于首页APP的特效等我完工了再贴出来吧,现在先把这个特效给分享出来,只是稍微改动了一点点而已。 先看效果图:我们先创建一个UIUtils,转换一些单位package com.lgl.test;import android.conte

刘桂林的博客 5286

Mathtype公式下标深度调整技巧:解决固定行距下的显示不全问题

本文针对在Word等文档中设置固定行距时,Mathtype公式下标显示不全的问题,提供了专业解决方案。核心在于调整Mathtype软件内部的“下标深度”参数,通过修改单个公式或批量格式化全文,使公式完美适配固定行距,确保下标清晰完整,且不影响文档整体排版。

pepsi的博客 1503

重复点击提交、产生多笔数据、保持数据只操作一次---->接口幂等性校验

幂等校验一、工作真实场景 + 常出现场景二、工作解决方案 + 百度解决方案 一、工作真实场景 + 常出现场景 真实场景:在一次工作中进行成品出库创建成品出库单时,手抖了一下,重复点击了两次确定(提交表单)。结果很神奇的发现居然产生了两笔一模一样的数据(流水号都一样),当时就很懵逼,稍作思考,想想应该是在同一时刻创建了两个出库单。感觉很有意思(因为之前没有遇到过,写代码的时候也没有考虑到这个问题的发生),后面换了一种方式复现场景:提交表单时多次点击Enter按钮,还是会产生多笔重复数据。 常见场景: 订单接

私聊前往站内信:https://i.youkuaiyun.com/#/msg/chat/weixin_44976692 6万+

Android水波纹特效的简单实现

转载地址http://www.jianshu.com/p/cba46422de67 水波纹特效,想必大家或多或少见过,在我的印象中,大致有如下几种: 支付宝 "咻咻咻" 式流量球 "荡漾" 式真实的水波纹效果,基于Bitmap处理式 今天我们主要讲一讲如何通过自定义View(以下简称WaveView)实现 "咻咻咻" 式的水波纹扩散效果,少废话,先看东西: 填充式水波纹

scott2017的博客 4617

【从零开始入门unity游戏开发之——C#篇37】进程、线程、C# 中实现多线程有多种方案和async/await异步编程

进程、线程、C# 中实现多线程有多种方案和async/await异步编程

向宇的博客,专注php/web全栈 unity游戏开发,欢迎大家评论纠错 1470

水波纹 android,Android特效之水波纹的实现

前言水波纹特效,想必大家或多或少见过,在我的印象中,大致有如下几种:支付宝 "咻咻咻" 式流量球 "荡漾" 式真实的水波纹效果,基于Bitmap处理式话不多说,先来看看效果:填充式水波纹,间距相等非填充式水波纹,间距相等非填充式水波纹,间距不断变大填充式水波纹,间距不断变小想必大家已经知道基本的原理了,就是用Canvas来画嘛,但可不是简单的画哦,请往下看。分析这种类型的水波纹,其实无非就是画圆而...

weixin_32915107的博客 692

【推荐100个unity插件】将UE的资源导出到unity使用—— Exporter for Unreal to/for Unity插件

Unreal to Unity导出器是一款帮助开发者将Unreal Engine项目转换为Unity的工具。文章详细介绍了使用步骤:1)安装虚幻引擎并创建项目;2)在Plugins文件夹中安装导出插件;3)导入UE资产到Content文件夹;4)配置导出参数并完成转换。文末推荐了多个Unity开发专栏,涵盖C#编程、2D/3D开发、特效制作等内容。作者向宇提供了博客地址,欢迎读者交流学习。该工具能有效提升项目迁移效率,适合需要跨引擎开发的用户使用。

向宇的博客,专注php/web全栈 unity游戏开发,欢迎大家评论纠错 855

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

Android特效专辑(十一)——仿水波纹流量球进度条控制器,实现高端大气的主流特效

Android特效专辑(十一)——仿水波纹流球进度条控制器,实现高端大气的主流特效 今天看到一个效果挺不错的,就模仿了下来,加上了一些自己想要的效果,感觉还不错的样子,所以就分享出来了,话不多说,上图 截图CircleView 这里主要是实现中心圆以及水波特效 package com.lgl.circleview;import android.content.Context; import

刘桂林的博客 7599

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

安卓开发水波纹【圆形波纹】特效

话不多说,先来看看效果: 源码位置【点击查看】

fengyeNom1的博客 603

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

Android 给View添加一个点击的水波纹特效

在drawable下新建一个标签为ripple 的文件 代码如下: <?xml version="1.0" encoding="utf-8"?> <ripple xmlns:android="http://schemas.android.com/apk/res/android" android:color="@color/RectPaitColor"//波纹颜色 ...

tiankong150的博客 686

android 炫酷特效,Android 特效之炫酷水波纹动画

效果图 示例代码1.初始化画笔public WaveView(Context context, AttributeSet attrs) {super(context, attrs);mPath = new Path();mPaint = new Paint();mPaint.setColor(Color.parseColor("#FF2877DD"));mPaint.setStyle(Paint....

weixin_39630813的博客 508

Android 特效之炫酷水波纹动画

效果图 示例代码 1.初始化画笔 public WaveView(Context context, AttributeSet attrs) { super(context, attrs); mPath = new Path(); mPaint = new Paint(); mPaint.setColor(Color.pa...

qq_37739140的博客 3125

android波纹动画,Android实现水波纹特效

最近需要做个类似于水波纹动画的效果,思考了一下不需要UI切个动态图,Android原生的技术利用动画或者自定义控件都可以实现,下面上个图类似于这样的效果下面请看第一种动画实现,这种方式较为简单些,就是利用3个ImageView不断地做缩放和渐变的动画。布局文件定义一下android:id="@+id/rl"android:layout_width="match_parent"android:lay...

weixin_39933336的博客 1102

Android 中Layout实现点击水波纹特效

Android5.0以后TextView,Button、TabLayout等控件默认都有点击水波纹效果,那布局类LinearLayout、RelativeLayout、TableLayout、FrameLayout、AbsoluteLayou如何实现A:使用 ripple、API-21+。B:三方库, RippleEffect或material-rippleC:android:background=

HKlsijun的博客 3789
上一篇: Java的运算符:取整,取绝对值,取余数
下一篇: React Native 开发第一节
jhonjson
博客等级 码龄11年 220粉丝 195原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值