文档章节

android 蒙版实现

李光正
 李光正
发布于 2015/10/15 14:54
字数 1586
阅读 22
收藏 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
大兴
私信 提问
Firefox 17 Beta 发布

Firefox 保持速度,紧接着将 17 推送到 Beta 更新渠道。 桌面版本更新有: 启用危险插件点击播放策略。对于有安全隐患的旧插件,用户在收到安全提醒后需要手动点击才可使用。进一步避免老版本...

oschina
2012/10/12
1K
22
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
android的蒙版开发

哪位大神做过android的蒙版开发呀,可不可以分享下怎么做

银粟
2015/10/22
117
0
做了2个月Android项目遇到了编码困难、UI难产、项目没有方向感,要怎样做才能继续下去?

今年4月份校招的到现今的这个公司实习,实习了两个月。说实话,两个月都不知道干了嘛,实习期间的工作是开发公司网站的Android客户端。属于独立开发的那种,没有产品经理、UI设计师,大概总经...

朗朗雪飘
2015/10/11
2.6K
17

没有更多内容

加载失败,请刷新页面

加载更多

Flink-数据流编程模型

1、抽象等级 Flink提供了不同级别的抽象来开发流/批处理应用程序。 1) 低层级的抽象 最低层次的抽象仅仅提供有状态流。它通过Process函数嵌入到DataStream API中。它允许用户自由地处理来自一...

liwei2000
23分钟前
1
0
Java开发Swing实战JFrame和JTabbedPane容器的用法详细解析

概述: 项目是一个桌面程序,涉及标签和按钮组件、布局管理器组件、面板组件、列表框和下拉框组件等组件,以及Swing事件处理机制。 下面先从最基础的界面开始。 /** * @author: lishuai * @...

金铭鼎IT教育
28分钟前
9
0
flask 之旅

环境 为了正确地跑起来,你的应用需要依赖许多不同的软件。 就算是再怎么否认这一点的人,也无法否认至少需要依赖Flask本身。 你的应用的运行环境,在当你想要让它跑起来时,是至关重要的。 ...

hblt-j
29分钟前
6
0
easyui的上传文件

记录一下自己亲手操刀easyui的心得:不用不知道,一用就问题多,网上查资料,有用的真的太少了 ——————————————————正文 FileBox,还是不错的讲真,至少我去自己写就gaga了...

anlve
30分钟前
4
0
如何做好SQLite 使用质量检测,让事故消灭在摇篮里

本文由云+社区发表 SQLite 在移动端开发中广泛使用,其使用质量直接影响到产品的体验。 常见的 SQLite 质量监控一般都是依赖上线后反馈的机制,比如耗时监控或者用户反馈。这种方式问题是: ...

腾讯云加社区
32分钟前
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部