美文网首页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