高亮说明控件

前言:

软件开发时常常须要对某些按钮进行说明,引导用户该怎么去操做软件。这种状况大部分是一个透明的遮罩层,遮罩层上有一部分高亮区显示要说明的按钮,按钮的某个方向上加上一个图片进行操做说明。好比说小面的效果。android

实现思路

  1. 在控件上覆盖上原有的控件截图
  2. 在控件上绘制基本集合图形,利用混合模式显示高亮区

编写代码

首先利用思路1的方式实现

  1. 编写一个自定义view,继承自view,下面直接上代码,看代码中的注释便可理解。git

    public class GuideView extends View {
         private Paint paint;
         //编写一个GuideBean,里面存放控件说明的信息,好比图片,要说明的控件等
         private GuideBean guideBean;
         
          public GuideView(Context context, AttributeSet attrs) {
             super(context, attrs);
         }
         
          @Override
         protected void onDraw(Canvas canvas) {
             super.onDraw(canvas);
             //若是集合中不存在控件说明,直接隐藏该view。
             if (guideBeans == null || guideBeans.size() == 0){
                 this.setVisibility(GONE);
                 return;
              }
             
             //Config是此view的配置类,下面会提到。这里的OPENMORE指是否在一个屏幕内显示多个控件说明
             if (Config.OPENMORE){
                 //一屏显示多个控件说明
                 canvas.drawBitmap(createDstBitmap(width,height), 0, 0, paint);
                 for (int i=0; i<guideBeans.size(); i++){
                     drawBuyView(canvas,guideBeans.get(i));
                 }
             }else {
                 //没点击一次,就播放下一个控件说明
                 drawBuyView(canvas,guideBean);
             }
         }
         
         //将要添加的控件说明集合设置进此view中,等待显示
         public void setGuideBeans(List<GuideBean> guideBeans){
             this.guideBeans = guideBeans;
             invalidate();
         }
         
         //当数据设置好后调用此方法显示控件说明
         public void showGuide(){
             //将隐藏中的该view设置为显示状态
             this.setVisibility(VISIBLE);
             if (guideBeans != null && guideBeans.size() !=0){
                 //将当前的说明设置为集合中的第一个对象。
                 guideBean = guideBeans.get(0);
             }
             invalidate();
          }
    }
    复制代码
  2. 绘制要说明控件的图片canvas

    /**
     * 绘制高亮区及说明图片
     * @param canvas
     * @param guideBean
     */
    public void drawBuyView(Canvas canvas,GuideBean guideBean){
        if (guideBean == null){
            return;
        }
        //若是是一屏显示多个控件说明,遮罩层在循环前绘制一边便可
        if (!Config.OPENMORE){
            canvas.drawBitmap(createDstBitmap(width,height), 0, 0, paint);
        }
        
        //绘制view的图像,即将view自己绘制成高亮区
        //须要注意的是,要说明的控件背景不可设置为透明背景,否在获取控件图片时背景也
        //是透明的,这样控件的颜色与遮罩层的颜色就一致了,起不到高亮的效果
        if (guideBean.getViewBitmap() != null){
            canvas.drawBitmap(guideBean.getViewBitmap(),guideBean.getRect().left,guideBean.getRect().top,paint);
        }
        //说明控件的中线坐标,用于计算说明图片的在x轴上的起始距离(距离屏幕左边距离)
        int centerLine = guideBean.getRect().left+(guideBean.getRect().right-guideBean.getRect().left)/2;
        //计算说明图片x轴上的起始位置
        int targetCenter = centerLine - guideBean.getBitmap().getWidth()/2;
        if (guideBean.getBitmap() != null){
            //执行绘制说明图片的方法
            drawShuoMingPic(canvas,guideBean,targetCenter);
        }
    }
    
     /**
     * 绘制控件说明
     * @param canvas
     * @param guideBean
     */
    private void drawShuoMingPic(Canvas canvas, GuideBean guideBean,int targetCenter) {
        //根据不一样的方位状况进行控件绘制。这里只写出绘制在控件底部的状况,所有的代码有点长,就不贴出来了。
        if (guideBean.getPosition() == Config.BOTTOM){
            canvas.drawBitmap(guideBean.getBitmap(),targetCenter+guideBean.getMarginLeft(),guideBean.getRect().bottom+guideBean.getMarginTop()+guideBean.getMarginBottom(),paint);
        }
    }
    复制代码
  3. 编写一个配置类,用于配置该view的属性bash

    /**
      * view的配置文件,务必在调用showGuide方法前配置完guideview
      */
     public static class Config{
         /**
          * 是否打开一个界面显示多个控件说明,默认是关闭的
          */
         public static boolean OPENMORE = false;
         
          /**
          * 配置遮罩层颜色
          */
         public static int COLOR = Color.parseColor("#99000000");
     }
    复制代码
  4. 编写GuideBean,这个类描述了全部的控件说明信息,好比padding,margin,控件的在屏幕上的位置等信息app

public class GuideBean{
    private Rect rect;
    private int img;
    private Bitmap bitmap;
    private Bitmap viewBitmap;
    private int marginTop,marginBottom,marginLeft,marginRight;
    private boolean isSimpleShape;
    private int position;
    private byte shape;

    /**
     *
     * @param img 要展现的说明图片
     * @param act 活动界面
     * @param view 想要出现高亮区的控件
     */
    public GuideBean(int img, Activity act, View view) {
        Rect rect = new Rect();
        //获取控件在屏幕中的坐标位置,此坐标位置包括了状态栏的高度和标题栏的高度,
        //因此后面矩阵rect中的top和bottom须要去除这两个高度的影响。去除方法在GuideViewUtils帮助类中
        view.getGlobalVisibleRect(rect);
        setRectInfo(rect,act);
        this.img = img;
        //获取控件说明图片
        bitmap = BitmapFactory.decodeResource(act.getResources(),img);
        this.rect = rect;
        //获取控件自己的图片
        this.viewBitmap = GuideViewUtils.loadBitmapFromView(view);
    }
    
    /**
     * 设置控件矩阵的顶部坐标和底部坐标,这两个坐标与状态栏和标题栏高度有关
     * @param rect 控件的矩阵
     * @param act 活动
     */
    public void setRectInfo(Rect rect,Activity act){
       rect.top = rect.top - GuideViewUtils.getStatusBarHeight(act) - GuideViewUtils.getInstance().getActionBarHeight(act);
       rect.bottom = rect.bottom - GuideViewUtils.getStatusBarHeight(act) - GuideViewUtils.getInstance().getActionBarHeight(act);
    }
    
    //下面时一堆get和set方法,不贴出来了。
  }
复制代码
  1. 获取状态栏高度,标题栏高度和view的图片(下面的方法在GuideViewUtils帮助类里面)
    /**
      * 获取状态栏高度
      * @param context
      * @return 状态栏高度
      */
     public static int getStatusBarHeight(Activity context){
         //判断存不存在状态栏
         WindowManager.LayoutParams params = context.getWindow().getAttributes();
         if ((params.flags & WindowManager.LayoutParams.FLAG_FULLSCREEN) == WindowManager.LayoutParams.FLAG_FULLSCREEN){
             //不存在状态栏直接返回0
             return 0;
         }else {
             //存在则获取状态栏高度
             int height = 0;
             int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
             if (resourceId > 0) {
                 height = context.getResources().getDimensionPixelSize(resourceId);
             }
             return height;
         }
     }
     
     /**
      * 获取 标题栏高度
      * @param activity
      * @return
      */
     public int getActionBarHeight(Activity activity){
         //判断传进来的activity是否是Activity,继承自Activity的活动是不带标题栏的
         //继承自AppCompatActivity的活动是带有标题栏的
         if (activity instanceof AppCompatActivity){
             //判断活动中是否存在标题栏,存在返回高度,不存在返回0
             if (((AppCompatActivity) activity).getSupportActionBar() != null){
                 return ((AppCompatActivity) activity).getSupportActionBar().getHeight();
             }else {
                 return 0;
             }
         }else if (activity instanceof Activity){
             if (activity.getActionBar() != null){
                 return activity.getActionBar().getHeight();
             }else {
                 return 0;
             }
         }else {
             return 0;
         }
     }
    复制代码

调用并显示控件说明

  1. 布局编写
    <com.libowu.guide.view.GuideView
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:id="@+id/guide"/>
    复制代码
  2. 设置控件说明集合
//说明一下,只有绘制view完成后才能够设置集合,oncreate中view并无绘制完成,因此控件的高度,在屏幕中的位置没法
//获取到,因此放到onWindowFocusChanged中执行了。不过onWindowFocusChanged是只要屏幕焦点变化时都会调用,不如锁屏
//开屏,切换先后台等都有肯能触发onWindowFocusChanged
@Override
 public void onWindowFocusChanged(boolean hasFocus) {
     super.onWindowFocusChanged(hasFocus);
     //将要说明的控件添加到集合中,让后给guideview设置数据便可
     guides = new ArrayList<>();
     guides.add(new GuideBean(R.mipmap.guide,this,textView, true, GuideView.Config.OVAL));
     guides.add(new GuideBean(R.mipmap.guide,this,textViewTwo,true, GuideView.Config.OVAL));
     guides.add(new GuideBean(R.mipmap.guide,this,textViewThree,true, GuideView.Config.OVAL));
     guide.setGuideBeans(guides);
 }
复制代码
  1. 显示控件说明
textViewTwo.setOnClickListener(new View.OnClickListener() {
         @Override
         public void onClick(View view) {
             //想要显示引导时,调用此方法便可显示
             guide.showGuide();
         }
     });
复制代码

引入依赖使用该view

  1. 项目的build.gradle中加入下面内容
allprojects {
     repositories {
         ....
         maven {url "https://jitpack.io"}
     }
 }
复制代码

2.app的build.gradle中加入依赖
implementation 'com.gitee.libowu:guideView:v0.0.4'maven

总结

这个项目只说了第一种思路,第二种思路并无说,由于代码有点多,因此先不写了,有兴趣的能够到码云上面clone项目到本地。码云地址ide

相关文章
相关标签/搜索