zoukankan      html  css  js  c++  java
  • 类似微信发图片的样式

    我们的设计要求聊天软件发图片做成微信那样,把图切成泡泡的形状,之前只用过circleimage,也就是切四个圆角,但是类似于气泡这种东西的那个小尾巴确实用函数画起来很困难,只好作罢,今天看到一开源代码有这个,于是着急做了个demo,分享下。

    前段时间有人问我关于怎么绘制不规则图形的问题。比如,如何像whatsApp那样绘制的聊天气泡图形。在这个系列文章中我们主要来关注一下如何实现不规则图形效果。

    在开始之前,我必须承认我忽略了问我这个问题的这个人。如果您正在阅读这篇文章,那么请与我联系,我会为你记上一功。感谢您激发我写这一系列文章的灵感。

    我们先从一个简单的不规则图形开始:一个带有圆角的矩形。有必要指出的是,圆角可以使用RoundRectShape Drawable实现(在API2.0里引入的)。但是,它不能实现之后我们要制作的所有效果,所以我们还是坚持使用自己的方法。

    这里要使用的第一种技术就是我们在Styling Android介绍过的Dynamic Icons——使用Alpha遮罩层实现。

    概念很简单,这里需要两张图片:第一张是我们需要显示在矩形中的图片,第二章是需要定义的矩形。然后我们使用一个Porter-Duff Alpha模式来进行图片结合。这个模式可以让我们从遮罩层中使用到透明像素的信息。

    这是我们需要使用到的图片:

    betty_sm

    mask_sm

    第一张是Betty,这篇文章的模特。第二张是定义圆角的遮罩层,这图片用绿色的原因是要保证遮罩层中的颜色不会被使用到(我们可不希望在转换的过程中让Betty变成绿色)。

    代码很简单:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    public Bitmap combineImages(Bitmap bgd, Bitmap fg) {
        Bitmap bmp;
      
        int width = bgd.getWidth() > fg.getWidth() ?
            bgd.getWidth() : fg.getWidth();
        int height = bgd.getHeight() > fg.getHeight() ?
            bgd.getHeight() : fg.getHeight();
      
        bmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        Paint paint = new Paint();
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP));
      
        Canvas canvas = new Canvas(bmp);
        canvas.drawBitmap(bgd, 0, 0, null);
        canvas.drawBitmap(fg, 0, 0, paint);
      
        return bmp;
    }

    现在我们就创建了一张匹配了原图和遮罩层的新图片。首先就先绘制遮罩层图片,然后就把可爱的Betty绘制上去,使用一个带有SRC_ATOP的PorterDuffXFerMode模式的paint对象。这样就可以使用背景遮罩层的透明像素,进而就可以准确绘制原图了。结果就像这样:

    part1

    看起来非常不错,我们可以实现预期的结果了,但是这个方法还有一些问题。

    首先,遮罩层的密度必须和原图一样,这点我们其实也可以对遮罩层进行缩放处理,但是缩放过度的话也会出现问题的。还有就是,如果原图和遮罩层的图比例不一样的话圆角也会出现变形。

    还有一个大问题是,这样不够高效。为了实现这个效果,我们需要载入两张图片到内存中,然后结合成一张新的图片。如果图片很大的话,这样我们就有出现OutOfMemoryError的危险。

    虽然这种技术还存在一些问题(比如不规则图形太复杂的话,用这种技术就有些困难了),但是还有会有解决方案的。这就是我们后面要说的,一种更高效的方式。我们在下一篇文章再见。

    这篇文章的所有代码在这里

    上面的博客是照抄别人的,自己又写了demo,把思路整理了下,用到了一个关键的BubbleImageHelper类,大家可以参考下

      1 package com.example.myimage;
      2 
      3 import android.content.Context;
      4 import android.graphics.Bitmap;
      5 import android.graphics.BitmapFactory;
      6 import android.graphics.Canvas;
      7 import android.graphics.Matrix;
      8 import android.graphics.Paint;
      9 import android.graphics.PorterDuff;
     10 import android.graphics.PorterDuffXfermode;
     11 import android.graphics.Rect;
     12 import android.graphics.Bitmap.Config;
     13 
     14 public class BubbleImageHelper {
     15     private Context context = null;
     16     private static BubbleImageHelper instance = null;
     17 
     18     public static synchronized BubbleImageHelper getInstance(Context c) {
     19         if (null == instance) {
     20             instance = new BubbleImageHelper(c);
     21         }
     22         return instance;
     23     }
     24 
     25     private BubbleImageHelper(Context c) {
     26         context = c;
     27     }
     28 
     29     private Bitmap getScaleImage(Bitmap bitmap, float width, float height) {
     30         if (null == bitmap || width < 0.0f || height < 0.0f) {
     31             return null;
     32         }
     33         Matrix matrix = new Matrix();
     34         float scaleWidth = width / bitmap.getWidth();
     35         float scaleHeight = height / bitmap.getHeight();
     36         matrix.postScale(scaleWidth, scaleHeight);
     37         Bitmap resizeBmp = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(),
     38                 bitmap.getHeight(), matrix, true);
     39         return resizeBmp;
     40     }
     41 
     42     public Bitmap getBubbleImageBitmap(Bitmap srcBitmap,
     43             int backgroundResourceID) {
     44         if (null == srcBitmap) {
     45             return null;
     46         }
     47         Bitmap background = null;
     48         background = BitmapFactory.decodeResource(context.getResources(),
     49                 backgroundResourceID);
     50         if (null == background) {
     51             return null;
     52         }
     53 
     54         Bitmap mask = null;
     55         Bitmap newBitmap = null;
     56         mask = srcBitmap;
     57 
     58         float srcWidth = (float) srcBitmap.getWidth();
     59         float srcHeight = (float) srcBitmap.getHeight();
     60         if (srcWidth < 300f && srcHeight < 500f) {
     61             srcWidth = 300f;
     62             srcHeight = (float) 500f;
     63             Bitmap tmp = getScaleImage(background, srcWidth, srcHeight);
     64             if (null != tmp) {
     65                 background = tmp;
     66             } else {
     67                 tmp = getScaleImage(srcBitmap, (float) 100f, (float) 100f);
     68                 if (null != tmp) {
     69                     mask = tmp;
     70                 }
     71             }
     72         }
     73 
     74         Config config = background.getConfig();
     75         if (null == config) {
     76             config = Bitmap.Config.ARGB_8888;
     77         }
     78 
     79         newBitmap = Bitmap.createBitmap(background.getWidth(),
     80                 background.getHeight(), config);
     81         Canvas newCanvas = new Canvas(newBitmap);
     82 
     83         newCanvas.drawBitmap(background, 0, 0, null);
     84 
     85         Paint paint = new Paint();
     86 
     87         paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP));
     88 
     89         int left = 0;
     90         int top = 0;
     91         int right = mask.getWidth();
     92         int bottom = mask.getHeight();
     93         if (mask.getWidth() > background.getWidth()) {
     94             left = (mask.getWidth() - background.getWidth()) / 2;
     95             right = mask.getWidth() - left;
     96         }
     97 
     98         if (mask.getHeight() > background.getHeight()) {
     99             top = (mask.getHeight() - background.getHeight()) / 2;
    100             bottom = mask.getHeight() - top;
    101         }
    102 
    103         newCanvas.drawBitmap(mask, new Rect(left, top, right, bottom),
    104                 new Rect(0, 0, background.getWidth(), background.getHeight()),
    105                 paint);
    106 
    107         return newBitmap;
    108     }
    109 }

    封装好了,使用起来就很简单,如下

    package com.example.myimage;
    
    import android.app.Activity;
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    import android.os.Bundle;
    import android.view.Menu;
    import android.view.MenuItem;
    import android.widget.ImageView;
    
    public class MainActivity extends Activity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            Bitmap bitmap = null;
            bitmap = BubbleImageHelper.getInstance(getApplicationContext())
                    .getBubbleImageBitmap(
                            BitmapFactory.decodeResource(getApplicationContext()
                                    .getResources(), R.drawable.mask),
                            R.drawable.bg);
            if (null != bitmap) {
                ((ImageView) findViewById(R.id.imageView1)).setImageBitmap(bitmap);
            }
        }
    }

    源码下载地址 http://download.csdn.net/detail/hongheqq/8198099

  • 相关阅读:
    Proof of Stake-股权证明 系列3
    共识算法的比较:Casper vs Tendermint
    我的友情链接
    我的友情链接
    我的友情链接
    我的友情链接
    我的友情链接
    我的友情链接
    我的友情链接
    我的友情链接
  • 原文地址:https://www.cnblogs.com/dongweiq/p/4121999.html
Copyright © 2011-2022 走看看