美文网首页Android开发Android开发经验谈Android技术知识
扣丁学堂Android开发实现扫一扫绘制指定区域透明区域

扣丁学堂Android开发实现扫一扫绘制指定区域透明区域

作者: 994d14631d16 | 来源:发表于2018-07-30 15:18 被阅读17次

  在实现扫一扫的功能的时候,我们需要绘制一个中间为透明的扫码框,其余部分为半透明。通常情况下,例如微信或者支付宝的扫码框都是矩形的,如果中间的扫码框是一个矩形,那么布局是很简单的,可是如果扫码框是一个圆角矩形,或者圆形等情况怎么办呢?这篇文章主要是记录绘制一个中间透明带圆角的矩形。

​  按照惯例,我们先来看看效果图:

  二、按照流程我们就开始来看看代码啦

  1、CustomDrawable,支持中间出现透明区域的drawable

  packageper.juan.scandome;

  importandroid.graphics.Canvas;

  importandroid.graphics.ColorFilter;

  importandroid.graphics.Paint;

  importandroid.graphics.Path;

  importandroid.graphics.PorterDuff;

  importandroid.graphics.PorterDuffXfermode;

  importandroid.graphics.drawable.Drawable;

  importandroid.support.annotation.NonNull;

  importandroid.support.annotation.Nullable;

  /**

  *支持中间出现透明区域的drawable

  *通过{@link#setSrcPath(Path)}设定透明区域的形状

  *Createdbyjuanon2018/07/20.

  */

  publicclassCustomDrawableextendsDrawable{

  privatePaintsrcPaint;

  privatePathsrcPath=newPath();

  privateDrawableinnerDrawable;

  publicCustomDrawable(DrawableinnerDrawable){

  this.innerDrawable=innerDrawable;

  srcPath.addRect(100,100,200,200,Path.Direction.CW);

  srcPaint=newPaint(Paint.ANTI_ALIAS_FLAG);

  srcPaint.setColor(0xffffffff);

  }

  /**

  *设置内部透明的部分

  *

  *@paramsrcPath

  */

  publicvoidsetSrcPath(PathsrcPath){

  this.srcPath=srcPath;

  }

  @Override

  publicvoiddraw(@NonNullCanvascanvas){

  innerDrawable.setBounds(getBounds());

  if(srcPath==null||srcPath.isEmpty()){

  innerDrawable.draw(canvas);

  }else{

  //将绘制操作保存到新的图层,因为图像合成是很昂贵的操作,将用到硬件加速,这里将图像合成的处理放到离屏缓存中进行

  intsaveCount=canvas.saveLayer(0,0,canvas.getWidth(),canvas.getHeight(),srcPaint,Canvas.ALL_SAVE_FLAG);

  //dst绘制目标图

  innerDrawable.draw(canvas);

  //设置混合模式

  srcPaint.setXfermode(newPorterDuffXfermode(PorterDuff.Mode.CLEAR));

  //src绘制源图

  canvas.drawPath(srcPath,srcPaint);

  //清除混合模式

  srcPaint.setXfermode(null);

  //还原画布

  canvas.restoreToCount(saveCount);

  }

  }

  @Override

  publicvoidsetAlpha(intalpha){

  innerDrawable.setAlpha(alpha);

  }

  @Override

  publicvoidsetColorFilter(@NullableColorFiltercolorFilter){

  innerDrawable.setColorFilter(colorFilter);

  }

  @Override

  publicintgetOpacity(){

  returninnerDrawable.getOpacity();

  }

  }

  (1)主要用到的技术是PorterDuffXfermode的PorterDuff.Mode.XOR模式

  (2)核心思想是先正常绘制出整个drawable,然后将指定的区域混合成透明色

  2、CustomLayout

  packageper.juan.scandome;

  importandroid.annotation.SuppressLint;

  importandroid.content.Context;

  importandroid.graphics.Path;

  importandroid.support.annotation.NonNull;

  importandroid.support.annotation.Nullable;

  importandroid.util.AttributeSet;

  importandroid.view.View;

  importandroid.widget.FrameLayout;

  /**

  *根据layout中子View的位置,确定局部透明区域

  *Createdbyjuanon2018/07/20.

  */

  publicclassCustomLayoutextendsFrameLayout{

  privateContextmContext;

  privateCustomDrawablebackground;

  publicCustomLayout(@NonNullContextcontext){

  super(context);

  initView(context,null,0);

  }

  publicCustomLayout(@NonNullContextcontext,@NullableAttributeSetattrs){

  super(context,attrs);

  this.mContext=context;

  initView(context,attrs,0);

  }

  publicCustomLayout(@NonNullContextcontext,@NullableAttributeSetattrs,intdefStyleAttr){

  super(context,attrs,defStyleAttr);

  initView(context,attrs,defStyleAttr);

  }

  @SuppressLint("NewApi")

  privatevoidinitView(@NonNullContextcontext,@NullableAttributeSetattrs,intdefStyleAttr){

  background=newCustomDrawable(getBackground());

  setBackground(background);

  }

  @Override

  protectedvoidonLayout(booleanchanged,intleft,inttop,intright,intbottom){

  super.onLayout(changed,left,top,right,bottom);

  resetBackgroundHoleArea();

  }

  @SuppressLint("NewApi")

  privatevoidresetBackgroundHoleArea(){

  Pathpath=null;

  //以子View为范围构造需要透明显示的区域

  Viewview=findViewById(R.id.iv_scan);

  if(view!=null){

  path=newPath();

  //矩形透明区域

  path.addRoundRect(view.getLeft(),view.getTop(),view.getRight(),view.getBottom(),dp2Px(mContext,10),dp2Px(mContext,10),Path.Direction.CW);

  }

  if(path!=null){

  background.setSrcPath(path);

  }

  }

  publicintdp2Px(Contextcontext,floatdp){

  finalfloatscale=context.getResources().getDisplayMetrics().density;

  return(int)(dp*scale+0.5f);

  }

  }

  3、然后在XML布局中声明我们的自定义View

  android:layout_width="match_parent"

  android:id="@+id/frame_layout"

  android:layout_height="match_parent">

  android:layout_width="match_parent"

  android:layout_height="match_parent"

  android:background="@mipmap/bg_image"/>

  android:layout_width="match_parent"

  android:id="@+id/layout"

  android:background="#8c565658"

  android:layout_height="match_parent">

  android:id="@+id/iv_scan"

  android:layout_width="200dp"

  android引用块内容center"/>

  以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值。

相关文章

网友评论

    本文标题:扣丁学堂Android开发实现扫一扫绘制指定区域透明区域

    本文链接:https://www.haomeiwen.com/subject/mfefvftx.html