文档章节

android 蒙版实现

李光正
 李光正
发布于 2015/10/15 14:54
字数 1586
阅读 18
收藏 1
Layout结构:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android=" http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:gravity="center_horizontal"
    >
    <TextView
        android:id="@+id/left"
        android:text="@string/left"
        android:textSize="18px"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:layout_marginTop="22px"
        />
    <TextView
        android:id="@+id/middle"
        android:text="@string/middle"
        android:textSize="40px"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_alignParentTop="true"
        />
<TextView
        android:id="@+id/right"
        android:text="@string/right"
        android:textSize="18px"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_alignParentTop="true"
        android:layout_marginTop="22px"
        />
    <ImageView
        android:id="@+id/mask"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:src="@drawable/mask"
        />
</RelativeLayout>

就是想要下面一个效果:
 

使用的蒙板是:
 


但是问题出现了, 原本期待出现的效果变成了下图:
 

看到了吗?左右两边应该是透明渐变的非常平滑的过渡变成了一条透明一条黑线的巨惨效果,相信你应该能想象到我拿这个效果去给设计师看的时候,他们的头上的黑线不比这少吧…

原因分析
为什么会出现上述的问题呢?那是因为在OPhone 1.5/Android 1.6之后的版本,带Alpha通道,支持透明的PNG24 的渲染是有问题的。在一般的手机上,都只支持到16位色,而这时系统会把PNG24降为PNG8来渲染,这样就出现了上面的惨不忍睹的情况。
所以这时候反而是低版本的手机上是渲染正常的,而这个结果相信是大家都不想看到的。那么有办法解决吗?当然有。

解决方案1 – 抖动(Dithering)

使用抖动,可以解决这个问题吗?
这里的抖动说的不是靠用户本身自己抖动,当频率和那些黑线的频率一致时,蒙板就会变成平滑的渐变…
其实是指使用加入噪点的方式,在过渡的中间进行”抖动 “使渐变更平滑。
设计师/美工可以在他们使用的PhotoShop里面设置加噪点或抖动,还有人特意为这个做了一个滤镜,好人啊。
而程序员有两种方式:
1 直接在代码里面写
ImageView v = (ImageView)findViewById(R.id.mask);
v.getDrawable().setDither(true);

2 使用xml定义drawable
<?xml version="1.0" encoding="UTF-8"?>
<nine-patch
    xmlns:android=" http://schemas.android.com/apk/res/android"
    android:src="@drawable/mask"
    android:dither="true" />
具体可以参见Android Tales的 http://android.amberfog.com/?p=247
于是加了抖动之后的效果:
 


结论: 失败,无论你怎么抖,还是黑线… 是那些大牛的方子不灵吗?No!他们针对的是渐变,不是透明的渐变!抖动的确可以使渐变更平滑,使原来会有间断线或色块的问题解决,但是不会使一个透明渐变的黑线消失。
解决方案2 – 代码生成图像
既然上面的方法失败了,直接用代码生成一个遮罩图呢?咱们可是程序员啊!
下面是生成渐变透明图的代码:
    public static Bitmap createLinear(Context context, int width, int height, int from_color, int to_color){
        Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        int[] data8888 = new int[width];
        makeRamp(premultiplyColor(from_color), premultiplyColor(to_color), width, data8888);
        bitmap.copyPixelsFromBuffer(makeBuffer(data8888, width));
        return bitmap;
    }

    private static void makeRamp(int from, int to, int n, int[] ramp8888){
        int r = getR32(from) << 23;
        int g = getG32(from) << 23;
        int b = getB32(from) << 23;
        int a = getA32(from) << 23;

        int dr = ((getR32(to) << 23) - r) / (n - 1);
        int dg = ((getG32(to) << 23) - g) / (n - 1);
        int db = ((getB32(to) << 23) - b) / (n - 1);
        int da = ((1 << 23) - a) / (n - 1);
        for (int i = 0; i < n; i++) {
            ramp8888[i] = pack8888(r >> 23, g >> 23, b >> 23, a >> 23);
            r += dr;
            g += dg;
            b += db;
            a += da;
        }
    }
这段不详细解释了,而且也是从Android的ApiDemos里面扒的,基本原理就是一组像素一组像素的设定颜色和Alpha值达到渐变透明的图片。
结论是? 又杯具了。失败的原因应该是这段代码生成的本质还是PNG8,不支持真正的透明。
Ok, 咱们可是程序员,还可以使用渐变的画笔吧:

public static Bitmap createLinearImage(Context context, int width, int height, int color0, int color1, float rate, boolean left) {
        //Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ALPHA_8);
        //Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_4444);
        //Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
        Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        Paint paint = new Paint();
        Paint paintShader = new Paint();
        LinearGradient shader;
        int w = Math.round(width*rate);
        if (left) {
            paint.setColor(color0);
            canvas.drawRect(0, 0, w, height, paint);
            shader = new LinearGradient(0, 0, width, 0, color0, color1, Shader.TileMode.CLAMP);
            paintShader.setShader(shader);
            canvas.drawRect(w, 0, width, height, paintShader);
        }else{
            shader = new LinearGradient(0, 0, width, 0, color0, color1, Shader.TileMode.CLAMP);
            paintShader.setShader(shader);
            canvas.drawRect(0, 0, width - w, height, paintShader);
            paint.setColor(color1);
            canvas.drawRect(width - w , 0, width, height, paint);
        }
        
        return bitmap;
    }

这段代码是使用了渐变效果的Painter来生成图像,注意我注释掉的那些图片格式,8888其实对应的就是PNG8, 别的是更挫的格式。

结论仍然是不好用。原因应该和上面的一样。

解决方案3 – 去掉透明
这个其实不算一个真正的解决方案,就是不要透明的蒙版,两边直接遮死,不会露出下面的文字。

但是对于一个想做出和IPhone的应用一样精致的程序员是不会接受这样绥靖的方案的。于是最后的解决方案终于到来了。

终极解决方案
Android平台可以使用xml来定义几种图像,其中就包括渐变图。
比如下面的xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android=" http://schemas.android.com/apk/res/android"
>
    <gradient
        android:startColor="#FF000000 "
        android:centerColor="#FF00000"
        android:endColor="#00000000"
        android:shape="rectangle"
        android:centerX="0.2"
        android:angle="0"
    />
</shape>

上面定义的图像翻译成中文就是,这是一张图,它从左到右渐变,开始到20%的地方都是不透明的黑色,从20%到最后开始渐变,变成纯透明的黑色。它的区域的形状是矩形。

所以咱们把这个xml保存到res/drawable目录下,ImageView的src就可以设置成这个文件了。再将原来的layout文件改成一左一右两张蒙版的ImageView, 分别使用上面的drawable和与之成左右镜像的drawble就可以达到最完美的效果了!

就是下面的图所示:

 


结论:使用xml来定义出来的drawble,可以达到完美的渲染。原因是啥呢?这个我也不知道… 估计要去问google的大牛们了。

我推测是前几种的方案系统实现的渲染代码有bug,或者是最后的方案的实现的渲染代码才是bug,也许那些大牛们认为有黑线的才是对的吧 : (

本文转载自:http://blog.csdn.net/liguangzhenghi/article/details/8151570

共有 人打赏支持
李光正
粉丝 5
博文 64
码字总数 0
作品 0
大兴
Android中点击空白区域控件自动隐藏(事件传递机制中的一个小例子)

随着android技术日趋成熟,android应用程序已经由刚开始的单纯效果展示变得越来越艺术话了,各种动画,各种布局层叠,那么由此就产生了一些问题,比如:一个listview的view的item点击时没有反...

xubohui
2013/12/19
0
0
SVG.js - 用于SVG操作和产生动画的一个轻量级js库

SVG.js是一个轻量级的JavaScript库,让您可以轻松地操纵SVG和让SVG产生动画。 SVG.js配有一个整体的方法,如创建,移动,居中,克隆等等。 SVG.js中包含了大量用于定义动画的方法,如移动、缩...

kiwifig
2013/05/26
0
0
Android7.0 分屏下 Activity 与 Fragment 生命周期(一)

小菜前段时间整理了一篇关于我们真的了解 Activity 与 Fragment 的生命周期吗?的小博文,整理了基础版的关于 Activity 与 Fragment 的生命周期。 后来又一次被一个大大神问到在 Android7.0...

阿策神奇
06/11
0
0
Android UI换皮肤或 白天黑夜模式

> 白天夜间模式场景,换肤框架 -- 关于三种『应用内主题切换』开源项目的一点思考- https://www.jianshu.com/p/2164fa5803b9 1.Theme的方案,在style文件中定义不同的主题即可 2.遍历View,对...

desaco
08/27
0
0
转: ios与android语音互通方案,类微信

Ios实现amr编解码 Feb 5th, 2012 介绍 学习ios第一个练手功能就是给已有产品加上语音通信功能,能够互通ios与android。这里给出自己的一些心得,希望能给他人一些参考。 资料搜集与参考 类似...

天下杰论
2014/10/30
0
0

没有更多内容

加载失败,请刷新页面

加载更多

为什么Java大神,都在看Spring Boot和Spring Cloud的书?

如果你是一名Java开发人员,并且最近正打算学习Spring Boot和Spring Cloud框架并寻找一些关于它们的最好的书籍,那么,你今天就来对地方了。 本文,我们将讨论一些学习Spring Boot和Spring ...

Java小铺
16分钟前
6
0
springboot logback日志配置

springboot 如果不使用外部tomcat的话,日志是需要自己配置的,不然的话就只有控制台的日志,但是日志又是我们在项目上了生产环境,出问题时,检查问题的唯一途径,所以我们要配置详细的日志...

曾大大胖
16分钟前
2
0
Linux服务器集体篡改时间的方法

Red Hat 虚拟化课程RH318,中小型公司使用的话,感觉可以匹敌OpenStack。手头上有一个VMware的映像,RHEV 3.5版的,只能把系统时间调整到2016年才能使用。Red Hat的RHEV已经更新到4.1版,不过...

大别阿郎
17分钟前
1
0
Tomcat启动异常:java.lang.ClassNotFoundException

警告: Name = mysqlDataSource Property maxActive is not used in DBCP2, use maxTotal instead. maxTotal default value is 8. You have set value of "100" for "maxActive" property, wh......

hengbao5
18分钟前
1
0
GO错误的一些处理(defer,recover,panic)

package main import("fmt""errors")func main() {num := 10fmt.Printf("num的类型%T, num的值%v, num的地址%v\n", num, num, &num)num2 := new(int) //返回一个指针//num...

汤汤圆圆
27分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部