android遮罩层引导页showCaseView的扩展及解析

本文介绍了对android遮罩层引导库showCaseView的扩展,扩展内容包括支持自定义布局和更灵活的设置选项。文章通过MaterialShowcaseView展示了如何创建和控制引导页面,包括布局的初始化、动画策略和目标视图的显示策略。同时,文章还讲解了使用本地SharedPreferences存储引导状态的方法以及配置和构建器的设计。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

android遮罩层引导页showCaseView的扩展及解析

前言:

首先感谢showcase引导页的这个lib,本blog对此lib进行了扩展,可以输入自定义layout或者通过代码对引导层中的布局属性进行设置;

快捷入口为: MaterialShowcaseView

内容:

效果图
在这里插入图片描述
在这里插入图片描述

先来回顾下原lib中的亮点:

  • 提供targetview的三种显示策略,CircleShape,NoShape,RectangleShape;
  • 提供多个引导页的延迟展示;Queue<ShowcaseView> mShowcaseQueue;
  • 提供两种引导动画,Fade和CircularReveal;

扩展功能及使用

去除了 CustomShowcaseView 中的固定布局,采用了设置自定义layout来设置多个引导页面;可使用自定义xml的layout,增加灵活性;

调用方式与原lib一致:

//显示引导页;
private void presentShowcaseSequenceByCustomStyle() {
        List<CustomShowcaseView> caseViews = new ArrayList<>();
        //添加不同特征的实现类;
        caseViews.add(FeedDetailActHelper.createMaterialShowcaseViewNeo(this, likeCustomView, 0));
        caseViews.add(FeedDetailActHelper.createMaterialShowcaseViewNeo(this, commentCustomView, 1));
        caseViews.add(FeedDetailActHelper.createMaterialShowcaseViewNeo(this, shareCustomView, 2));
        caseViews.add(FeedDetailActHelper.createMaterialShowcaseViewNeo(this, layoutFavorite, 3));
		
        CustomMaterialShowcaseSequence sequence = new CustomMaterialShowcaseSequence(this, SHOWCASE_ID_BOTTOM);
		//添加至队列的容器内;
        for (CustomShowcaseView view : caseViews) {
            sequence.addSequenceItem(view);
        }
		//显示对应的showcase;
        sequence.start();
    }

//具体的showcase构造类
public static CustomShowcaseView createMaterialShowcaseViewNeo(Activity activity, View tartgetView,int mode) {
        return new CustomShowcaseView.Builder(activity)
                .setLayoutShowCase(createStrategyByType(mode))
                .setTarget(tartgetView)
                .setDismissOnTouch(true)
                .setMaskColour(BPlusApplication.mContext.getResources().getColor(R.color.show_case_color))
                .singleUse(SHOWCASE_ID_BOTTOM) // provide a unique ID used to ensure it is only shown once
                .withRectangleShape(false)
                .build();
    }
	//对不同的case,显示不同layout的不同实现类;
public static CustomShowcaseView.ShowcaseDraw createStrategyByType(int mode) {
     CustomShowcaseView.ShowcaseDraw mShowcaseDrawImpl = null;
     switch (mode) {
         case 0:
             mShowcaseDrawImpl = new ShowcaseDrawFeedImpl();
             break;
         case 1:
             mShowcaseDrawImpl = new ShowcaseDrawFeedImpl.ShowcaseDrawFeed2Impl();
             break;
         case 2:
             mShowcaseDrawImpl = new ShowcaseDrawFeedImpl.ShowcaseDrawFeed3Impl();
             break;
         case 3:
             mShowcaseDrawImpl = new ShowcaseDrawFeedImpl.ShowcaseDrawFeed4Impl();
             break;
     }
     return mShowcaseDrawImpl;
 }

原理解析:

CustomShowcaseView自定义viewgroup,用于显示不同布局的view;
设置不同的布局,将子实现的布局和绘制抽象出去,同一控制显示;

  • 将不同的引导布局作为一个单独的策略;
/**
     * 子实现的布局及绘制接口;
     */
    public interface ShowcaseDraw {
    	//当前showcase的layout布局id;
        int getLayoutId();
		//初始化layout;
        void initView(CustomShowcaseView contentView);
		//在布局改变时监听,以mTarget view的包装类为锚,可自定义设置view的精确布局;
        void customLayout(Target mTarget);
    }

可自定义设置layout显示;
getLayout返回一个layout id;
initview 初始化layout;
customlayout 设置其中某些view的相对于targetview的位置;

eg:
@Override public void customLayout(Target mTarget) { mImgArrow.setTranslationX(mTarget.getPoint().x - mImgArrow.getMeasuredWidth()/2); }

  • getViewTreeObserver().addOnGlobalLayoutListener 添加对布局改变事件的监听
    监听布局改变,设置mTargetview,并且此事件中view的高度宽度可以获取到; 可通过ShowcaseDraw设置不同实现的具体布局或者变换属性;

  • onDraw 具体绘制方法

protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //判断是否需要绘制;
        // don't bother drawing if we're not ready
        if (!mShouldRender) return;
        
        // get current dimensions
        final int width = getMeasuredWidth();
        final int height = getMeasuredHeight();
        // don't bother drawing if there is nothing to draw on
        if (width <= 0 || height <= 0) return;

		//建立装载画布,用于相交模式下对mTarget的形状显示;
        // build a new canvas if needed i.e first pass or new dimensions
        if (mBitmap == null || mCanvas == null || mOldHeight != height || mOldWidth != width) {

            if (mBitmap != null) mBitmap.recycle();

            mBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);

            mCanvas = new Canvas(mBitmap);
        }

        // save our 'old' dimensions
        mOldWidth = width;
        mOldHeight = height;

        // clear canvas
        mCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);

        // draw solid background
        mCanvas.drawColor(mMaskColour);

        // Prepare eraser Paint if needed
        if (mEraser == null) {
            mEraser = new Paint();
            mEraser.setColor(0xFFFFFFFF);
            mEraser.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
            mEraser.setFlags(Paint.ANTI_ALIAS_FLAG);
        }
		//将具体的绘制交给不同的实现类,可实现对targetview的各种不同形状的显示;
        // draw (erase) shape
        mShape.draw(mCanvas, mEraser, mXPosition, mYPosition, mShapePadding);
        //绘制装载画布;
        // Draw the bitmap on our views  canvas.
        canvas.drawBitmap(mBitmap, 0, 0, null);
    }
  • 加入到当前activity和从activity中移除

show:

((ViewGroup) activity.getWindow().getDecorView()).addView(this); 添加至activity中,设置重绘,添加动画;

hide:

//从activity中移除,并回收相关的资源操作;
if (getParent() != null && getParent() instanceof ViewGroup) {
            ((ViewGroup) getParent()).removeView(this);
        }

onDetachedFromWindow 回调detach方法,设置PrefsManager的记录值,回调给mDetachedListener,如果是多个layout
的显示,detachListener 通过showNextItem重新显示下一个layout;

  • 动画策略
//显示layout的动画;
 void animateInView(View target, Point point, long duration, AnimationStartListener listener);
 //隐藏layout的动画;
 void animateOutView(View target, Point point, long duration, AnimationEndListener listener);

提供两个动画
ViewAnimationUtils.createCircularReveal() 水波纹动画;
ObjectAnimator.ofFloat 透明度属性动画;
  • targetview的相交形状策略
public interface Shape {
    /**
     * Draw shape on the canvas with the center at (x, y) using Paint object provided.
     */
    void draw(Canvas canvas, Paint paint, int x, int y, int padding);
    /**
     * Get width of the shape.
     */
    int getWidth();
    /**
     * Get height of the shape.
     */
    int getHeight();
    /**
     * Update shape bounds if necessary
     */
    void updateTarget(Target target);
}

提供了3种策略,
CircleShape: 显示targetview圆形区域;
NoShape: 不做任何处理;
RectangleShape: targetview的方形区域;

本地sharepreference的存储;
设置两种状态 start 和 finish 状态记录多种layout点击一次回到start状态,detach时设置finish状态;

配置类和构建者
建立ShowcaseConfig保存可设置的属性,用于便捷统一设置showcase的属性; 构建者用于快速设置属性;

###后记

详细见代码,希望与大家共同进步;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值