Android使用BitmapShader图形渲染实现圆形、圆角和椭圆自定义图片View
一、概述
Android实现圆角矩形,圆形或者椭圆等图形,一般主要是个自定义View加上使用Xfermode实现的。实现圆角图片的方法其实不少,常见的就是利用Xfermode,Shader。本文直接继承ImageView,使用BitmapShader方法来实现圆形、圆角和椭圆的绘制,等大家看我本文的方法后,其他的类似形状也就都能举一反三来来画出来了。
二、效果图:
三、BitmapShader简介
BitmapShader是Shader的子类,可以通过Paint.setShader(Shader shader)进行设置、
我们这里只关注BitmapShader,构造方法:
mBitmapShader = new BitmapShader(bitmap, TileMode.CLAMP, TileMode.CLAMP);
参数1:bitmap
参数2,参数3:TileMode;
TileMode的取值有三种:
CLAMP 拉伸
REPEAT 重复
MIRROR 镜像
如果大家给电脑屏幕设置屏保的时候,如果图片太小,可以选择重复、拉伸、镜像;
重复:就是横向、纵向不断重复这个bitmap
镜像:横向不断翻转重复,纵向不断翻转重复;
拉伸:这个和电脑屏保的模式应该有些不同,这个拉伸的是图片最后的那一个像素;横向的最后一个横行像素,不断的重复,纵项的那一列像素,不断的重复;
public BitmapShader(Bitmap bitmap,Shader.TileMode tileX,Shader.TileMode tileY)
调用这个方法来产生一个画有一个位图的渲染器(Shader)。
bitmap 在渲染器内使用的位图
tileX The tiling mode for x to draw the bitmap in. 在位图上X方向花砖模式
tileY The tiling mode for y to draw the bitmap in. 在位图上Y方向花砖模式
TileMode:(一共有三种)
CLAMP :如果渲染器超出原始边界范围,会复制范围内边缘染色。
REPEAT :横向和纵向的重复渲染器图片,平铺。
MIRROR :横向和纵向的重复渲染器图片,这个和REPEAT 重复方式不一样,他是以镜像方式平铺。
四、自定义圆形、圆角和椭圆的图片View的实现
1. 测量View的大小
代码如下 | 复制代码 |
@Override } |
2、设置BitmapShader和画笔Paint
代码如下 | 复制代码 |
/** } else if (mType == TYPE_ROUND || mType == TYPE_OVAL) { } |
3.最后就是绘制出来圆角、圆形和椭圆的图片,肯定在onDraw里面啦,根本原理就是使用了上面mBitmapShader渲染的画笔来绘制
代码如下 | 复制代码 |
@Override if (null == getDrawable()) { |
五、视图布局实现
这个很简单,就是3个自定义的view:
代码如下 | 复制代码 |
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout <com.czm.viewdrawtest.XCRoundAndOvalImageView <com.czm.viewdrawtest.XCRoundAndOvalImageView <com.czm.viewdrawtest.XCRoundAndOvalImageView </ScrollView> |
六、使用和测试自定义View
上面直接绘制的自定义View写完了,下面就是使用这个View了,使用方法和普通的ImageView一样,当作普通控件使用即可。
代码如下 | 复制代码 |
package com.czm.viewdrawtest;
private XCRoundAndOvalImageView circleImageView;//圆形图片 |
在上一篇中我们讲了Android使用BitmapShader图形渲染实现圆形、圆角和椭圆自定义图片View,本篇我们来讲讲另外一个更为常见的图形渲染方法Xfermode。
一:简介:
在上一篇《Android使用BitmapShader图形渲染实现圆形、圆角和椭圆自定义图片View》中,采用BitmapShader方法实现自定义的圆形、圆角等自定义ImageView,这篇我们将采用更为常见的Xfermode渲染模式方案来实现圆形、圆角和椭圆样式的ImageView,同样本实例也是直接继承ImageView,
这样可以省很多事情,比如测量步骤,以及不需要自己去写设置图片的方法,本文使用Xfermode模式中的DST_IN模式来实现要达到的效果,当然大家也可以采用其他的模式,比如SRC_IN等都可以实现该效果。
(照例完整源代码在文章的最后给出下载地址哈)
二:效果图:
三、Xfermode渲染模式简介:
xfermode影响在Canvas已经有的图像上绘制新的颜色的方式
* 正常的情况下,在图像上绘制新的形状,如果新的Paint不是透明的,那么会遮挡下面的颜色.
* 如果新的Paint是透明的,那么会被染成下面的颜色
下面的Xfermode子类可以改变这种行为:
AvoidXfermode 指定了一个颜色和容差,强制Paint避免在它上面绘图(或者只在它上面绘图)。
PixelXorXfermode 当覆盖已有的颜色时,应用一个简单的像素XOR操作。
PorterDuffXfermode 这是一个非常强大的转换模式,使用它,可以使用图像合成的16条Porter-Duff规则的任意一条来控制Paint如何与已有的Canvas图像进行交互。
这里不得不提到那个经典的图:
上面的16种模式的说明如下:
从上面我们可以看到PorterDuff.Mode为枚举类,一共有16个枚举值:
1.PorterDuff.Mode.CLEAR
所绘制不会提交到画布上。
2.PorterDuff.Mode.SRC
显示上层绘制图片
3.PorterDuff.Mode.DST
显示下层绘制图片
4.PorterDuff.Mode.SRC_OVER
正常绘制显示,上下层绘制叠盖。
5.PorterDuff.Mode.DST_OVER
上下层都显示。下层居上显示。
6.PorterDuff.Mode.SRC_IN
取两层绘制交集。显示上层。
7.PorterDuff.Mode.DST_IN
取两层绘制交集。显示下层。
8.PorterDuff.Mode.SRC_OUT
取上层绘制非交集部分。
9.PorterDuff.Mode.DST_OUT
取下层绘制非交集部分。
10.PorterDuff.Mode.SRC_ATOP
取下层非交集部分与上层交集部分
11.PorterDuff.Mode.DST_ATOP
取上层非交集部分与下层交集部分
12.PorterDuff.Mode.XOR
异或:去除两图层交集部分
13.PorterDuff.Mode.DARKEN
取两图层全部区域,交集部分颜色加深
14.PorterDuff.Mode.LIGHTEN
取两图层全部,点亮交集部分颜色
15.PorterDuff.Mode.MULTIPLY
取两图层交集部分叠加后颜色
16.PorterDuff.Mode.SCREEN
取两图层全部区域,交集部分变为透明色
四、自定义圆形、圆角和椭圆的ImageView的实现
1、测量View的大小,对圆形作特殊处理
代码如下 | 复制代码 |
/** * 测量view的大小 */ @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // TODO Auto-generated method stub super.onMeasure(widthMeasureSpec, heightMeasureSpec); //如果类型是圆形,则强制设置view的宽高一致,取宽高的较小值 if(mType == TYPE_CIRCLE){ int width = Math.min(getMeasuredWidth(),getMeasuredHeight()); setMeasuredDimension(width, width); } } |
2、绘制不同图形的Bitmap,供onDraw()绘制的时候用
代码如下 | 复制代码 |
/** * 绘制不同的图形Bitmap */ private Bitmap getDrawBitmap(){ Bitmap bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); paint.setColor(Color.BLACK); if(mType == TYPE_CIRCLE) {//绘制圆形 canvas.drawCircle(getWidth() / 2, getWidth() / 2, getWidth() / 2, paint); }else if(mType == TYPE_ROUND) {//绘制圆角矩形 canvas.drawRoundRect(new RectF(0, 0, getWidth(), getHeight()), mRoundBorderRadius, mRoundBorderRadius, paint); }else if(mType == TYPE_OVAL ){ //绘制椭圆 canvas.drawOval(new RectF(0, 0, getWidth(), getHeight()), mPaint); } return bitmap; } |
3、在onDraw()中绘制出来
代码如下 | 复制代码 |
/** * 绘制view的内容 */ @Override protected void onDraw(Canvas canvas) { // TODO Auto-generated method stub //从缓存中取出bitmap Bitmap bmp = (mBufferBitmap == null ? null:mBufferBitmap.get()); if(bmp == null || bmp.isRecycled()){ //如果没有缓存存在的情况 //获取drawable Drawable drawable = getDrawable(); //获取drawable的宽高 int dwidth = drawable.getIntrinsicWidth(); int dheight = drawable.getIntrinsicHeight(); Log.v("czm","dwidth="+dwidth+",width="+getWidth()); if(null != drawable){ bmp = Bitmap.createBitmap(getWidth(), getHeight(), Config.ARGB_8888); float scale = 1.0f; //创建画布 Canvas drawCanvas = new Canvas(bmp); //按照bitmap的宽高,以及view的宽高,计算缩放比例;因为设置的src宽高 //比例可能和imageview的宽高比例不同,这里我们不希望图片失真; if(mType == TYPE_CIRCLE) {//如果是圆形 scale = getWidth() * 1.0F / Math.min(dwidth, dheight); }else if (mType == TYPE_ROUND || mType == TYPE_OVAL) {//如果是圆角矩形或椭圆 // 如果图片的宽或者高与view的宽高不匹配,计算出需要缩放的比例; //缩放后的图片的宽高,一定要大于我们view的宽高;所以我们这里取大值; scale = Math.max(getWidth() * 1.0f / dwidth, getHeight() * 1.0f / dheight); } Log.v("czm","scale="+scale); //根据缩放比例,设置bounds,即相当于做缩放图片 drawable.setBounds(0, 0, (int)(scale * dwidth), (int)(scale * dheight)); drawable.draw(drawCanvas); //获取bitmap,即圆形、圆角或椭圆的bitmap if(mMaskBitmap == null || mMaskBitmap.isRecycled()){ mMaskBitmap = getDrawBitmap(); } //为paint设置Xfermode 渲染模式 mPaint.reset(); mPaint.setFilterBitmap(false); mPaint.setXfermode(mXfermode); //绘制不同形状 drawCanvas.drawBitmap(mMaskBitmap, 0, 0,mPaint); mPaint.setXfermode(null); //将准备好的bitmap绘制出来 canvas.drawBitmap(bmp, 0, 0, null); //bitmap缓存起来,避免每次调用onDraw,分配内存 mBufferBitmap = new WeakReference<Bitmap>(bmp); } }else{ //如果缓存还存在的情况 mPaint.setXfermode(null); canvas.drawBitmap(bmp, 0.0f, 0.0f, mPaint); return; } } |
4、因为使用了弱引用的缓存技术,所以需要在重写invalidate()方法中做些释放回收资源等处理:
代码如下 | 复制代码 |
/** * 因为使用了缓存技术,所以需要在invalidate中做些回收释放资源的处理 */ @Override public void invalidate() { // TODO Auto-generated method stub mBufferBitmap = null; if(mMaskBitmap != null){ mMaskBitmap.recycle(); mMaskBitmap = null; } super.invalidate(); } |
五、视图布局的实现:
代码如下 | 复制代码 |
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout <com.czm.myroundimageview.XCRoundImageViewByXfermode <com.czm.myroundimageview.XCRoundImageViewByXfermode <com.czm.myroundimageview.XCRoundImageViewByXfermode </ScrollView> |
六、使用和测试自定义ImageView
上面直接绘制的自定义ImageView写完了,下面就是使用这个自定义的ImageView了,使用方法和普通的ImageView一样,当作普通控件使用即可。
代码如下 | 复制代码 |
package com.czm.myroundimageview; import android.app.Activity; public class MainActivity extends Activity { private XCRoundImageViewByXfermode circleImageView;//圆形图片 } |
以下是本人整理出来的几篇关于Android Studio开发环境使用的教程,希望您通过这几篇文章的学习,能够掌握Android开发神器Android Studio的使用
[图文]Android Studio下载安装及配置开发环境教程
http://www.111cn.net/sj/android/74261.htm
win7X64下Android Stuido安装及搭建开发环境问题解决
http://www.111cn.net/sj/android/74265.htm
mac下载安装Android Studio配置开发环境教程
http://www.111cn.net/sj/android/74262.htm
总结android studio注意事项及打不开等问题解决方法
http://www.111cn.net/sj/android/74264.htm
小结Android Studio常用设置说明教程
http://www.111cn.net/sj/android/74263.htm
总结Android Studio导入项目的几种方法
http://www.111cn.net/sj/android/74260.htm
[最新图文版]如何将项目从eclipse迁移到android studio?
http://www.111cn.net/sj/android/74224.htm
实现系统重启的APK需要system的权限,在AndroidManifest.xml中增加android:sharedUserId="android.uid.system",再修改签名即可;
具体方法参考:
点击打开链接
1、使用PowerManager来实现:
代码:
private void rebootSystem(){
PowerManager pManager=(PowerManager) getSystemService(Context.POWER_SERVICE);
pManager.reboot("");
}
2、发送REBOOT广播:
代码:
private void rebootSystem(){
Intent reboot = new Intent(Intent.ACTION_REBOOT);
reboot.putExtra("nowait", 1);
reboot.putExtra("interval", 1);
reboot.putExtra("window", 0);
sendBroadcast(reboot);
}
我想使用 ACTION_SEND 共享图片+文字,我运行了下面的代码,暂时只能共享图片,无法共享文字,我如何才能共享?
代码如下 | 复制代码 |
private Uri imageUri; private Intent intent; imageUri = Uri.parse("android.resource://" + getPackageName() + "/drawable/" + "ic_launcher"); intent = new Intent(); intent.setAction(Intent.ACTION_SEND); intent.putExtra(Intent.EXTRA_TEXT, "Hello"); intent.putExtra(Intent.EXTRA_STREAM, imageUri); intent.setType("image/*"); startActivity(intent); |
//如何才能共享图片?
处理方法
你可以共享下面的代码:
代码如下 | 复制代码 |
String shareBody = "Here is the share content body"; Intent sharingIntent = new Intent(android.content.Intent.ACTION_SEND); sharingIntent.setType("text/plain"); sharingIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, "Subject Here"); sharingIntent.putExtra(android.content.Intent.EXTRA_TEXT, shareBody); startActivity(Intent.createChooser(sharingIntent, getResources().getString(R.string.share_using))); |
所以你的全部代码(图片+文本)需要变成
代码如下 | 复制代码 |
private Uri imageUri; private Intent intent; imageUri = Uri.parse("android.resource://" + getPackageName() + "/drawable/" + "ic_launcher"); intent = new Intent(Intent.ACTION_SEND); //text intent.putExtra(Intent.EXTRA_TEXT, "Hello"); //image intent.putExtra(Intent.EXTRA_STREAM, imageUri); //type of things intent.setType("*/*"); //sending startActivity(intent); |
相关文章
使用PHP+JavaScript将HTML页面转换为图片的实例分享
这篇文章主要介绍了使用PHP+JavaScript将HTML元素转换为图片的实例分享,文后结果的截图只能体现出替换的字体,也不能说将静态页面转为图片可以加快加载,只是这种做法比较interesting XD需要的朋友可以参考下...2016-04-19- 这篇文章主要介绍了C#从数据库读取图片并保存的方法,帮助大家更好的理解和使用c#,感兴趣的朋友可以了解下...2021-01-16
- 今天小编在这里就来给各位Photoshop的这一款软件的使用者们来说说把古装美女图片转为细腻的工笔画效果的制作教程,各位想知道方法的使用者们,那么下面就快来跟着小编一...2016-09-14
- 这篇文章主要介绍了Python 图片转数组,二进制互转操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-03-09
- php如何实现抓取网页图片,相较于手动的粘贴复制,使用小程序要方便快捷多了,喜欢编程的人总会喜欢制作一些简单有用的小软件,最近就参考了网上一个php抓取图片代码,封装了一个php远程抓取图片的类,测试了一下,效果还不错分享...2015-10-30
- 下面我们来看一篇关于Android子控件超出父控件的范围显示出来方法,希望这篇文章能够帮助到各位朋友,有碰到此问题的朋友可以进来看看哦。 <RelativeLayout xmlns:an...2016-10-02
- 这篇文章主要给大家介绍了关于C#创建自定义控件及添加自定义属性和事件使用的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用C#具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧...2020-06-25
jquery左右滚动焦点图banner图片鼠标经过显示上下页按钮
jquery左右滚动焦点图banner图片鼠标经过显示上下页按钮...2013-10-13- 下面小编就为大家带来一篇利用JS实现点击按钮后图片自动切换的简单方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧...2016-10-25
- 本文实例讲述了JS实现自定义简单网页软键盘效果。分享给大家供大家参考,具体如下:这是一款自定义的简单点的网页软键盘,没有使用任何控件,仅是为了练习JavaScript编写水平,安全性方面没有过多考虑,有顾虑的可以不用,目的是学...2015-11-08
- 这篇文章主要为大家详细介绍了js实现上传图片及时预览的相关资料,具有一定的参考价值,感兴趣的朋友可以参考一下...2016-05-09
- Photoshop的这一款软件小编相信很多的人都已经是使用过了吧,那么今天小编在这里就给大家带来了用Photoshop软件制作枪战电影海报的教程,想知道制作步骤的玩家们,那么下面...2016-09-14
Android开发中findViewById()函数用法与简化
findViewById方法在android开发中是获取页面控件的值了,有没有发现我们一个页面控件多了会反复研究写findViewById呢,下面我们一起来看它的简化方法。 Android中Fin...2016-09-20- 如果我们的项目需要做来电及短信的功能,那么我们就得在Android模拟器开发这些功能,本来就来告诉我们如何在Android模拟器上模拟来电及来短信的功能。 在Android模拟...2016-09-20
- 夜神android模拟器如何设置代理呢?对于这个问题其实操作起来是非常的简单,下面小编来为各位详细介绍夜神android模拟器设置代理的方法,希望例子能够帮助到各位。 app...2016-09-20
- 为了增强android应用的用户体验,我们可以在一些Button按钮上自定义动态的设置一些样式,比如交互时改变字体、颜色、背景图等。 今天来看一个通过重写Button来动态实...2016-09-20
- 如果我们要在Android应用APP中加载html5页面,我们可以使用WebView,本文我们分享两个WebView加载html5页面实例应用。 实例一:WebView加载html5实现炫酷引导页面大多...2016-09-20
- 深入理解Android中View和ViewGroup从组成架构上看,似乎ViewGroup在View之上,View需要继承ViewGroup,但实际上不是这样的。View是基类,ViewGroup是它的子类。本教程我们深...2016-09-20
- 下面我们来看一篇关于Android自定义WebView网络视频播放控件开发例子,这个文章写得非常的不错下面给各位共享一下吧。 因为业务需要,以下代码均以Youtube网站在线视...2016-10-02
- java开发的Android应用,性能一直是一个大问题,,或许是Java语言本身比较消耗内存。本文我们来谈谈Android 性能优化之MemoryFile文件读写。 Android匿名共享内存对外A...2016-09-20