Android自定义控件(七)——ShapeDrawable实现放大镜效果

举报
择城终老 发表于 2021/07/27 00:31:03 2021/07/27
【摘要】 本文目录 什么是ShapeDrawableOvalShape的基本用法放大镜效果实现 什么是ShapeDrawable ShapeDrawable是一种常见的Drawable,可以理解为通过颜色来构造的图形,它既可以是纯色的图形,也可以是具有渐变效果的图形。 ShapeDrawable有两个构造函数,分别是: ShapeDrawable() S...


实现效果

什么是ShapeDrawable

ShapeDrawable是一种常见的Drawable,可以理解为通过颜色来构造的图形,它既可以是纯色的图形,也可以是具有渐变效果的图形。

ShapeDrawable有两个构造函数,分别是:

ShapeDrawable()
ShapeDrawable(Shape s)

  
 
  • 1
  • 2

ShapeDrawable使用过程中,需要与Shape对象关联起来,所以,当我们使用第一个构造函数的时候,就需要额外的调用如下代码,关联Shape:

ShapeDrawable.setShape(Shape shape)

  
 
  • 1

所以从这里我们可以看到,我们还是直接使用第二个构造函数最方便,但有一点需要注意,Shape是一个基类,并没有具体实现,并不能直接传递Shape对象,在我们使用的过程中,要么自己继承实现,要么使用它的派生类:

1.RectShape:构造一个矩形Shape
2.ArcShape:构造一个扇形Shape
3.OvalShape:构造一个椭圆Shape
4.RoundRectShape:构造一个圆角矩形Shape,可带有镂空的矩形效果
5.PathShape:构造一个可根据路径绘制的Shape

OvalShape的基本用法

今天介绍的放大镜效果的实现,使用的就是OvalShape来构造,所以我们先来写一个简单的程序,看看如何使用这个OvalShape,直接上代码:

public class OvalShapeView extends View { private ShapeDrawable shapeDrawable;//定义一个ShapeDrawable /*** * 初始化 */ private void init(){ setLayerType(LAYER_TYPE_SOFTWARE,null);//关闭硬件加速 this.shapeDrawable=new ShapeDrawable(new OvalShape());//绘制一个椭圆形的ShapeDrawable this.shapeDrawable.setBounds(new Rect(50,50,200,100));//定位椭圆位置 this.shapeDrawable.getPaint().setColor(Color.GREEN);//显示颜色为绿色 } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); this.shapeDrawable.draw(canvas); } public OvalShapeView(Context context) { super(context); this.init(); } public OvalShapeView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); this.init(); } public OvalShapeView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); this.init(); }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

其中setBounds()用来指定当前ShapeDrawable在当前控件中的显示位置,而getPaint()就是获取ShapeDrawable自带的画笔,然后设置画笔参数,来更改其显示效果,使用起来与直接定义的Paint类似,比如这里的setColor(),还有即将用到的setShader()。这段代码显示的效果如下:
OvalShape其他几个的用法雷同,这里就不在赘述了。

放大镜效果实现

基本用法小编已经介绍的比较清楚了,下面我们来实现我们今天的终极目标,如何实现Android中的放大镜效果,首先我们还是要自定义一个View,然后定义成员变量,进行初始化,代码如下:

public class LoupeView extends View { private Bitmap bitmap;//获取原图片 private ShapeDrawable shapeDrawable;//创建一个 private final Matrix matrix=new Matrix();//矩阵运算 private static final int RADIUS=160;//半径 private static final int TIMES=3;//放大倍数 private void init(){ setLayerType(LAYER_TYPE_SOFTWARE,null);//禁止硬件加速 } public LoupeView(Context context) { super(context); this.init(); } public LoupeView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); this.init(); } public LoupeView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); this.init(); }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

这里我们定义了一个bitmap方便后续设置背景,以及设置放大效果,还有ShapeDrawable,矩阵运算matrix进行移动ShapeDrawable,半径RADIUS,倍数TMES。

接着,我们需要绘制背景到自定义控件中,所以我们需要在OnDraw()函数中进行绘制操作,代码如下:

@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if(this.bitmap==null){ Bitmap bmp= BitmapFactory.decodeResource(getResources(),R.drawable.background);//获取原图片 this.bitmap=Bitmap.createScaledBitmap(bmp,getWidth(),getHeight(),false);//根据原图片创建一个和屏幕宽高相等的Bitmap BitmapShader bitmapShader=new BitmapShader( Bitmap.createScaledBitmap(this.bitmap,bitmap.getWidth()*TIMES,bitmap.getHeight()*TIMES,true),//按比例进行缩放图片 Shader.TileMode.CLAMP, Shader.TileMode.CLAMP); this.shapeDrawable=new ShapeDrawable(new OvalShape());//构造一个椭圆图形 this.shapeDrawable.getPaint().setShader(bitmapShader);//填充 this.shapeDrawable.setBounds(0,0,RADIUS*2,RADIUS*2);//因为椭圆的宽高都是一样的,所以是个圆形 } canvas.drawBitmap(this.bitmap,0,0,null); this.shapeDrawable.draw(canvas); }

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

这里我们通过判断bitmap是否为空,才知道是否设置了背景,如果没有背景,我们获取到原图像,然后通过createScaledBitmap()将源图像缩放到控件大小,这里小编设置的控件大小为match_parent,其实就是屏幕的宽高。

同时,通过BitmapShader设置图片的放大效果,然后就是上面介绍的OvalShape来构造一个圆形,因为这里设置的椭圆形宽高都是RADIUS*2,所以他是一个圆形。最后,将图片画到控制之中,然后把放大后的该图片圆形显示区域的ShapeDrawable也画上去。

@Override
public boolean onTouchEvent(MotionEvent event) { final int x=(int)event.getX();//获取手指X坐标 final int y=(int)event.getY();//获取手指Y坐标 //将ShapeDrawable移动到手指所显示人区域 this.matrix.setTranslate(RADIUS-x*TIMES,RADIUS-y*TIMES); this.shapeDrawable.getPaint().getShader().setLocalMatrix(this.matrix);
	//设置ShapeDrawable位置 this.shapeDrawable.setBounds(x-RADIUS,y-RADIUS,x+RADIUS,y+RADIUS); invalidate();//重绘 return true;
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

这段代码是放大镜的核心代码,我们先来理解一个概念,我们都知道上面我们设置了原图像的大小为手机的整个屏幕,假设小编的手指按住了了屏幕上的某个点(x,y),那么图片放大三倍后,这个点在什么位置?
第一步
当然是(3x,3y),因为放大是均匀放大的,所以放大后的点在(3x,3y)是毫无问题的,但是ShapeDrawable是从左上角开始平铺的,那么没放大之前,肯定从(0,0)开始,所以我们需要将整个bitmapShader向左上角移动3x,3y的距离,左上X,Y轴的移动方向都是负值,所以左上移动的距离就是(-3x,-3y),所以移动后的ShapeDrawable的左上角坐标就是(-3x,-3y)。
第二步
但是我们画圆形都是从中心点开始画的,所以我们需要在X,Y轴各加上一个半径,就变成了(-3x+RADIUS,-3y+RADIUS),也就是上面的this.matrix.setTranslate代码,然后通过setBounds()根据手指位置为中心,画一个圆形,这样我们的放大镜效果就完全实现了。

如果写的还可以,欢迎大家给个小小的赞支持一下,非常感谢!

本文Github源码下载地址:点击下载

文章来源: liyuanjinglyj.blog.csdn.net,作者:李元静,版权归原作者所有,如需转载,请联系作者。

原文链接:liyuanjinglyj.blog.csdn.net/article/details/103213176

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。