本文来自网易云社区

作者:孙有军

老需求

我们经常会有需求就是View消失的效果,这里我们说的消失往往是全部消失,我们可能采用一个alpha动画,在指定的时间内消失掉View,出现则实现相反的动画。我们一般都采用如下的实现:

采用tween动画实现:

private void alphaTween() {AlphaAnimation alpha = new AlphaAnimation(1.0f, 0.0f);alpha.setDuration(300);imageView.startAnimation(alpha);
}

或者采用属性动画实现:

private void alphaOB() {ObjectAnimator animator = ObjectAnimator.ofFloat(imageView, "alpha", 1.0f, 0.0f).setDuration(300);animator.start();
}

也可能采用xml来实现。

新需求

但是这里我们需要的不是上面的效果,你是在逗我??不是上面的效果,你说这么多。我们需求如下,这里我们用两个图来展示:

左边是原始图片,右边是处理后的图片。可以看到从下到上越来越淡,顶部就已经像消失了一样。说道这里很多人肯定会联想到图片的滤镜效果。但是这里实现的方式简单的多。

实现

这里我们写一个demo来实现这个效果。既然是在对View进行处理,那这里我们就先对一张图片进行处理。之后在扩展。

既然我们需要将图片变淡消失,肯定是需要合成了什么效果。那Android里面一般合成我们都采用什么方式呐?

Xfermode

Android里面我们可以采用Xfermode来实现图片的合成,比如我们可以实现各种各样的头像,例如圆形头像。那这里我们需要采用哪种mode?

这里先draw是dest,后draw是src,我们需要的是将dest露出,同时将src产生的效果合成到dest上,那这里我们需要用的是DST_IN效果。

上面图示表示一方是全透明的,其实还需要结合Mode定义来完全理解该效果,Mode的计算方式如下:

public enum Mode {/** [0, 0] */CLEAR       (0),    /** [Sa, Sc] */SRC         (1),    /** [Da, Dc] */DST         (2),    /** [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] */SRC_OVER    (3),    /** [Sa + (1 - Sa)*Da, Rc = Dc + (1 - Da)*Sc] */DST_OVER    (4),    /** [Sa * Da, Sc * Da] */SRC_IN      (5),    /** [Sa * Da, Sa * Dc] */DST_IN      (6),    /** [Sa * (1 - Da), Sc * (1 - Da)] */SRC_OUT     (7),    /** [Da * (1 - Sa), Dc * (1 - Sa)] */DST_OUT     (8),    /** [Da, Sc * Da + (1 - Sa) * Dc] */SRC_ATOP    (9),    /** [Sa, Sa * Dc + Sc * (1 - Da)] */DST_ATOP    (10),    /** [Sa + Da - 2 * Sa * Da, Sc * (1 - Da) + (1 - Sa) * Dc] */XOR         (11),    /** [Sa + Da - Sa*Da,Sc*(1 - Da) + Dc*(1 - Sa) + min(Sc, Dc)] */DARKEN      (16),    /** [Sa + Da - Sa*Da,Sc*(1 - Da) + Dc*(1 - Sa) + max(Sc, Dc)] */LIGHTEN     (17),    /** [Sa * Da, Sc * Dc] */MULTIPLY    (13),    /** [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] */SCREEN      (14),    /** Saturate(S + D) */ADD         (12),OVERLAY     (15);Mode(int nativeInt) {        this.nativeInt = nativeInt;}    /*** @hide*/public final int nativeInt;
}

从效果图上我们可以看到,图片消失的效果,不是整块消失,而是部分效果,就是效果是有一个渐变的过程。那这里我们需要合成的效果应该是一个渐变效果的图片。比如从全透明到全不透明。

代码实现

我们已经分析了全部需要的效果,那就最终写代码来看看最后的效果。

public class FadingPic extends View {    private Paint paint;    private Bitmap bitmap;    private int height;    private int width;    public FadingPic(Context context) {        super(context);init(context, null);}    public FadingPic(Context context, @Nullable AttributeSet attrs) {        super(context, attrs);init(context, attrs);}    public FadingPic(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);init(context, attrs);}    private void init(Context context, AttributeSet attrs) {bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.beautify);width = bitmap.getWidth();height = bitmap.getHeight();paint = new Paint();paint.setAntiAlias(true);paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));paint.setShader(new LinearGradient(0, 0, 0, height, 0x00000000, 0xff000000, Shader.TileMode.CLAMP));}    @Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);setMeasuredDimension(2 * width, height);}    @Overrideprotected void onDraw(Canvas c) {        super.onDraw(c);c.drawBitmap(bitmap, 0, 0, null);// 原始图片c.saveLayer(width, 0, width * 2, height, null, Canvas.ALL_SAVE_FLAG);c.drawBitmap(bitmap, width, 0, null);c.drawRect(width, 0, width * 2, height, paint);c.restore();}
}

我们直接操作了本地的一张图片。先draw出原图,在draw出合成后效果图。

1,定义了Xfermode为PorterDuff.Mode.DST_IN 2,给paint设置一个线性渐变的shader,透明图从全透明到全不透明,平铺模式为CLAMP 3,这里一定要在新的Layer中进行操作,否则只是叠加效果

实现2

上面我们采用在新的Layer进行操作,如果不在新的Layer只是叠加效果,那不采用Layer是否有方式可以实现?当然是可以的。这里我们改变一下当前的代码再新创建一个bitmap:

package com.demo.opengl.widget;import android.content.Context;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.Canvas;import android.graphics.LinearGradient;import android.graphics.Paint;import android.graphics.PorterDuff;import android.graphics.PorterDuffXfermode;import android.graphics.Shader;import android.support.annotation.Nullable;import android.util.AttributeSet;import android.view.View;import com.demo.opengl.R;/*** Created by hzsunyj on 2017/8/9.*/public class FadingPic extends View {    private Paint paint;    private Bitmap bitmap;    private Bitmap wapperBitmap;    private int height;    private int width;    private Canvas canvas;    public FadingPic(Context context) {        super(context);init(context, null);}    public FadingPic(Context context, @Nullable AttributeSet attrs) {        super(context, attrs);init(context, attrs);}    public FadingPic(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);init(context, attrs);}    private void init(Context context, AttributeSet attrs) {bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.beautify);width = bitmap.getWidth();height = bitmap.getHeight();paint = new Paint();paint.setAntiAlias(true);paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));paint.setShader(new LinearGradient(0, 0, 0, height, 0x00000000, 0xff000000, Shader.TileMode.CLAMP));        // new wapperBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);canvas = new Canvas(wapperBitmap);}    @Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);setMeasuredDimension(2 * width, height);}    @Overrideprotected void onDraw(Canvas c) {        super.onDraw(c);c.drawBitmap(bitmap, 0, 0, null);// 原始图片//        c.saveLayer(width, 0, width * 2, height, null, Canvas.ALL_SAVE_FLAG);//        c.drawBitmap(bitmap, width, 0, null);//        c.drawRect(width, 0, width * 2, height, paint);//        c.restore();canvas.drawBitmap(bitmap, 0, 0, null);canvas.drawRect(0, 0, width, height, paint);c.drawBitmap(wapperBitmap, width, 0, null);}
}

这里大部分代码是相同的,只是现将效果合成到一个新的bitmap,最后再将bitmap draw到屏幕上。

有什么用?

到这里也许你会问,这个需求没什么用啊!哪有这样需求。那这里我们就举个栗子。比如我们有一个列表页,当最上的条目滚动消失的时候,不是硬生生的消失,而是比较自然的消失。

比如上面,我们向上滚动顶部就有一个明显的被切掉的效果。不太友好。那我们可以处理成如下效果:

顶部一个渐变消失的效果。不会显的太突兀。

实现

之前我们实现了图片的部分消失效果,那这里我们怎么处理,比如这个RecyclerView,是针对每一行来进行处理?这样是不是很麻烦,又这种bind状态,还有各种重用,感觉问题比较多。前面的图片的方式根本不能重用啊!!

那这里我们怎么实现呐?我们是否可以不对item实现效果,而是针对整个RecyclerView来实现?

public class FadingRecyclerView extends RecyclerView {    private Paint paint;    private int height;    private int width;    public FadingRecyclerView(Context context) {        super(context);init(context, null);}    public FadingRecyclerView(Context context, @Nullable AttributeSet attrs) {        super(context, attrs);init(context, attrs);}    public FadingRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {        super(context, attrs, defStyle);init(context, attrs);}    private void init(Context context, AttributeSet attrs) {paint = new Paint();paint.setAntiAlias(true);paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));paint.setShader(new LinearGradient(0, 0, 0, 160, 0x00000000, 0xff000000, Shader.TileMode.CLAMP));}    @Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {        super.onSizeChanged(w, h, oldw, oldh);height = h;width = w;}    @Overridepublic void draw(Canvas c) {c.saveLayer(0, 0, width, height, null, Canvas.ALL_SAVE_FLAG);        super.draw(c);c.drawRect(0, 0, width, 160, paint);c.restore();}}

我们重写了RecyclerView,在draw函数中合成了效果,这里RecyclerView是一个ViewGroup,需要复写draw函数,而不是onDraw。

副产物

前面我们说过,如果不在新的Layer里面合成只会产生叠加效果,那这个叠加效果有什么用呐? 我们可以来实现倒影效果,他也是阶梯渐变的,那这里我们就来实现一下倒影效果。主要的区别为是否在新的layer里面实现。

public class FadingPic extends View {    private Paint paint;    private Paint paint1;    private Bitmap bitmap;    private Bitmap rotateBitmap;    private int height;    private int width;    public FadingPic(Context context) {        super(context);init(context, null);}    public FadingPic(Context context, @Nullable AttributeSet attrs) {        super(context, attrs);init(context, attrs);}    public FadingPic(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);init(context, attrs);}    private void init(Context context, AttributeSet attrs) {bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.beautify);width = bitmap.getWidth();height = bitmap.getHeight();paint = new Paint();paint.setAntiAlias(true);paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));paint.setShader(new LinearGradient(0, 0, 0, height, 0x00000000, 0xff000000, Shader.TileMode.CLAMP));Matrix matrix = new Matrix();matrix.setScale(1, -1);        //matrix.setRotate(180); 不能形成镜像效果rotateBitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);paint1 = new Paint();paint1.setAntiAlias(true);paint1.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));paint1.setShader(new LinearGradient(0, height, 0, 2 * height, 0xff000000, 0x00000000, Shader.TileMode.CLAMP));}    @Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);setMeasuredDimension(2 * width, 2 * height);}    @Overrideprotected void onDraw(Canvas c) {        super.onDraw(c);c.drawBitmap(bitmap, 0, 0, null);// 原始图片c.saveLayer(width, 0, width * 2, height, null, Canvas.ALL_SAVE_FLAG);c.drawBitmap(bitmap, width, 0, null);c.drawRect(width, 0, width * 2, height, paint);c.restore();        // 倒影c.drawBitmap(rotateBitmap, 0, height, null);c.drawRect(0, height, width, 2 * height, paint1);}
}

这里可以看到主要是将图片反转,注意这里不能采用旋转,旋转不会产生镜像效果。其他的都与之前的代码没有区别。那最终我们来看看实现的效果:

Done

如果有人有更简单的方式,可以探讨探讨。

网易云免费体验馆,0成本体验20+款云产品!

更多网易研发、产品、运营经验分享请访问网易云社区

相关文章:
【推荐】 市场调研中数据分析之道

Android View部分消失效果实现相关推荐

  1. Android仿QQ消息拖拽黏连消失效果,气泡爆炸效果

    公司需要这个效果,看了很多博客,根据自己项目的需要写出来的一个完整的过程. 拖拽控件代码 根据手势拖动的位置利用贝塞尔曲线算法画出控件 package cn.stike.bubble.stickbub ...

  2. android view禁用,Android 禁止ViewPager的自带滑动效果

    由于最近在做墨水屏的相关工作,ViewPager自带的滑动效果在墨水屏上表现的很不好,残影太重了.所以禁止自带的滑动效果,用接口来接管相关逻辑实现自处理. import android.content ...

  3. android中仿qq最新版抽屉,Android 自定义View实现抽屉效果

    Android 自定义View实现抽屉效果 说明 这个自定义View,没有处理好多点触摸问题 View跟着手指移动,没有采用传统的scrollBy方法,而是通过不停地重新布局子View的方式,来使得子 ...

  4. Android 自定义 圆环,Android自定义view实现圆环效果实例代码

    先上效果图,如果大家感觉不错,请参考实现代码. 重要的是如何实现自定义的view效果 (1)创建类,继承view,重写onDraw和onMesure方法 public class CirclePerc ...

  5. 代码android点击效果,GitHub - likaiyuan559/TouchEffects: Android View点击特效TouchEffects,几行代码为所有控件添加点击效果...

    Android 点击特效TouchEffects TouchEffects能够帮助你更快速方便的增加点击时候的效果,TouchEffects的目标是打造一个稳定.全面.且能更方便的自定义及个性化的一款 ...

  6. android波纹效果弹窗,Android自定义View实现波纹效果

    Android自定义View实现波纹效果 时间:2017-05-27     来源:移动互联网学院 1.引言:随着Android智能手机的普及,Android应用得到了大力支持,而Android应用的 ...

  7. Android 雪花飘落动画效果 自定义View

    在码农的世界里,优美的应用体验,来源于程序员对细节的处理以及自我要求的境界,年轻人也是忙忙碌碌的码农中一员,每天.每周,都会留下一些脚印,就是这些创作的内容,有一种执着,就是不知为什么,如果你迷茫,不 ...

  8. android 动态创建view,react-native动态创建Android View 无效果

    问题描述 react-native动态创建Android View 无效果,我想在react-native里面直接点击函数进行创建,也就是通过module中的方法创建View 问题出现的环境背景及自己 ...

  9. android 循环弹幕,Android自定义View实现弹幕效果

    原标题:Android自定义View实现弹幕效果 在很多视频直播中都有弹幕功能,而安卓上没有简单好用的弹幕控件,本文介绍一个自定义弹幕view的demo. 效果图: 思路: 自定义Textitem类表 ...

最新文章

  1. swift string,Int,Double相互转换
  2. linux gcc安装
  3. spring序列化_使用@JsonIdentityInfo的Spring自定义序列化器
  4. 【项目.源码】深度学习实现任意风格任意内容的极速风格迁移
  5. ElasticSearch学习(四):可视化管理之Kibana
  6. 共享单车为什么这么重?
  7. 数学问题(三):最小公倍数、最大公约数
  8. esp连接服务器的协议,【零知ESP8266教程】WIFI TCP协议通信 TCP服务器示例
  9. 资源白朴收藏:图片、 视频、音频、字体、PPT模板类、动态图、壁纸、图标
  10. 2021认证杯 第二阶段 思路加代码
  11. 斯特林公式 (Stirling公式)
  12. [转载]创建、部署和调试 Apache Geronimo 应用程序
  13. php获取qq头像地址,获取 QQ 头像地址,并且不暴露 QQ 号
  14. FZU1892接水管游戏-BFS加上简单的状态压缩和位运算处理
  15. linux 文件追加,如何在Linux中将文本内容追加到文件末尾?
  16. 2022百度之星程序设计大赛 - 复赛 1001 子序列
  17. js 判断字符串是中文、数字、大小写字母
  18. python包离线安装教程_离线安装python包(附示例:featuretools)
  19. 《Qt5+安装包制作(Qt Installer Framework)》
  20. #2. 小明的成绩单

热门文章

  1. ubuntu软件的卸载
  2. Cortex-M3 VS ARM7
  3. mongoDB常用查询更新删除语句
  4. mongodb数据迁移设置方法
  5. SQL必知必会 - 创建表的联结
  6. 删除页面引入的js或者css文件
  7. 帝国CMS对接百度小程序实现文章自动收录的方法
  8. 硅光电子器件模拟:“RSoft光电器件设计仿真技术与应用”
  9. Android开发扫一扫功能,Android使用ZXing实现扫码功能
  10. 安师大计算机系导师,安徽师范大学数学计算机科学学院导师介绍:陈付龙