IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> 用户引导页简单应用 -> 正文阅读

[移动开发]用户引导页简单应用

前言

不能做铺路人,做个引路人也好~
此文着重讲解张鸿洋大神的HighLightView的使用细节,大佬的库用过不少,或多或少的与产品业务有所不同,或者设计瑕疵的地方,无可厚非,此时作为以为优秀的百度开发者,我们应该有阅读甚至修改源码的能理,这样才能举一反三,融会贯通。

  1. 结合kotlin的函数式编程,言简意赅,闭包且简洁,一撸到底,墙裂推荐一波~
   
    var mHightLight: HighLight? = null
    var mOneModeLightView: HighLight? = null
    var mTwoModeLightView: HighLight? = null
 	/*
    * 新手指引: 
     * 注释:
     * @author maqi
     * created at 2021/11/30 10:13
     */
    private fun newUserGuide2SOr2T() {

        val offest = DensityUtils.dp2pxFloat(requireContext(), 2f)
        val customShape = object : BaseLightShape(0F, 0F, 5f) {
            override fun resetRectF4Shape(viewPosInfoRectF: RectF?, dx: Float, dy: Float) {
                viewPosInfoRectF?.offset(offest, offest)
            }

            override fun drawShape(bitmap: Bitmap, viewPosInfo: HighLight.ViewPosInfo) {
                val canvas = Canvas(bitmap)
                val paint = Paint(Paint.ANTI_ALIAS_FLAG)
                paint.isDither = true
                paint.isAntiAlias = true
                paint.color = Color.argb(100, 255, 255, 255)
                if (blurRadius > 0) {
                    paint.maskFilter = BlurMaskFilter(blurRadius, BlurMaskFilter.Blur.SOLID)
                }
                val rectF = viewPosInfo.rectF
                rectF.left -= offest
                rectF.top -= offest

                canvas.drawRect(rectF, paint)

                val bgBitmap = BitmapUtils.drawableToBitmap(requireContext(),
                        R.drawable.shape_radius_board_2dp,
                        rectF.width().toInt(),
                        rectF.height().toInt()
                )
                canvas.drawBitmap(bgBitmap!!, rectF.left, rectF.top, paint)

//                val bgBitmap = ImageFileCache.getBitmap(
//                        requireContext(),
//                        R.drawable.guide_dotted_square
//                )
//                val scaleBitmap = BitmapUtils.scaleBitmap(bgBitmap, rectF.width().toInt(), rectF.height().toInt())
//                canvas.drawBitmap(scaleBitmap!!, rectF.left, rectF.top, paint)
            }
        }

        if (true == mHightLight?.isShowing) {
            mHightLight?.remove()
        }
        if (true == mOneModeLightView?.isShowing) {
            mOneModeLightView?.remove()
        }
        if (true == mTwoModeLightView?.isShowing) {
            mTwoModeLightView?.remove()
        }

        val showTwoMode = fun() {
          
            mTwoModeLightView = HighLight(requireContext()).also { twoModeLightView ->
                twoModeLightView.autoRemove(false)
                        .intercept(true)
                        .addHighLight(R.id.yyyyy, R.layout.xxxxx, object : OnBaseCallback(offest) {
                            override fun getPosition(rightMargin: Float, bottomMargin: Float, rectF: RectF, marginInfo: HighLight.MarginInfo) {
                                val width = DensityUtils.dp2px(requireContext(), 80f)
                                val centerX = rectF.centerX()
                                marginInfo.leftMargin = centerX - width / 2F
                                marginInfo.topMargin = rectF.top + rectF.height() + offset
                            }
                        }, customShape)
                        /*下一步*/
                        .addHighLight(R.id.yyyyy, R.layout.xxxxx, object : OnBaseCallback(offest) {
                            override fun getPosition(rightMargin: Float, bottomMargin: Float, rectF: RectF, marginInfo: HighLight.MarginInfo) {
                                marginInfo.leftMargin = rightMargin - rectF.width() / 2
                                marginInfo.bottomMargin = bottomMargin + offset
                            }
                        }, object : BaseLightShape() {
                            override fun drawShape(bitmap: Bitmap?, viewPosInfo: HighLight.ViewPosInfo?) {

                            }

                            override fun resetRectF4Shape(viewPosInfoRectF: RectF?, dx: Float, dy: Float) {
                            }
                        })
                        .setOnShowCallback {
                            val hightLightView = twoModeLightView.getHightLightView()

                            /*注意此处 源代码中设置 布局ID 为 ID*/
                            val twoModeView = hightLightView.findViewById<View>(R.layout.xxxxx)

                            val next = hightLightView.findViewById<View>(R.id.next)
                            val nextTv = hightLightView.findViewById<TextView>(R.id.next_tv)
                            next.setOnClickListener {
                                twoModeView.visibility = View.GONE
                                showTwoSeeMode(true)
                                /*再次点击 关闭*/
                                nextTv.setText(R.string.know)
                                next.setOnClickListener {
                                    SharePreferenceUtil.setFirstUserUseTwo(requireContext(), false)
                                    needNewUserGuid = true
                                    twoModeLightView.remove()
                                    twoModePopup?.dismiss()
                                }
                            }
                        }
            }.show()
        }

        val showOneMode = fun() {
             
            mOneModeLightView= HighLight(requireContext()).also { oneModeLightView ->
                oneModeLightView.autoRemove(false)
                        .intercept(true)
                        .addHighLight(R.id.yyyyy, R.layout.xxxxx, object : OnBaseCallback(offest) {
                            override fun getPosition(rightMargin: Float, bottomMargin: Float, rectF: RectF, marginInfo: HighLight.MarginInfo) {
                                Log.d("showOneMode", "" + rectF.width())
                                Log.d("showOneMode", "" + rectF.height())
                                Log.d("showOneMode", "" + rectF.top)
                                Log.d("showOneMode", "" + rectF.bottom)
                                val width = DensityUtils.dp2px(requireContext(), 224f)
                                val centerX = rectF.centerX()
                                marginInfo.leftMargin = centerX - width / 2F
                                marginInfo.topMargin = rectF.top + rectF.height() + offset
                            }
                        }, customShape)
                        /*下一步*/
                        .addHighLight(R.id.yyyyy, R.layout.xxxxx, object : OnBaseCallback(offest) {
                            override fun getPosition(rightMargin: Float, bottomMargin: Float, rectF: RectF, marginInfo: HighLight.MarginInfo) {
                                marginInfo.leftMargin = rightMargin - rectF.width() / 2
                                marginInfo.bottomMargin = bottomMargin + offset
                            }
                        }, object : BaseLightShape() {
                            override fun drawShape(bitmap: Bitmap?, viewPosInfo: HighLight.ViewPosInfo?) {

                            }

                            override fun resetRectF4Shape(viewPosInfoRectF: RectF?, dx: Float, dy: Float) {
                            }
                        })
                        .setOnShowCallback {
                            val hightLightView = oneModeLightView.getHightLightView()

                            val next = hightLightView.findViewById<View>(R.id.next)
                            val nextTv = hightLightView.findViewById<TextView>(R.id.next_tv)
                            nextTv.setText(R.string.know)
                            next.setOnClickListener {
                              
                                needNewUserGuid = true
                                oneModeLightView.remove()
                            }
                        }
            }.show()
        }

        mHightLight = HighLight(requireContext()).also { highLight ->
            highLight.autoRemove(false)//设置背景点击高亮布局自动移除为false 默认为true
                    .intercept(true)//设置拦截属性为false 高亮布局不影响后面布局的滑动效果
//                    .enableNext()//开启next模式并通过show方法显示 然后通过调用next()方法切换到下一个提示布局,直到移除自身
                    //.anchor(drawer_layout)
                    .addHighLight(R.id.yyyyy, R.layout.xxxxx, OnBottomPosCallback(), customShape)
                    .addHighLight(R.id.yyyyy, R.layout.xxxxx, object : OnBaseCallback(offest) {
                        override fun getPosition(rightMargin: Float, bottomMargin: Float, rectF: RectF, marginInfo: HighLight.MarginInfo) {
                            marginInfo.leftMargin = rectF.right - rectF.width() + offset * 2
                            marginInfo.bottomMargin = bottomMargin + rectF.height() + offset
                        }
                    }, customShape)
                    .addHighLight(R.id.yyyyy, R.layout.xxxxx, object : OnBaseCallback(offest) {
                        override fun getPosition(rightMargin: Float, bottomMargin: Float, rectF: RectF, marginInfo: HighLight.MarginInfo) {
                            val width = DensityUtils.dp2px(requireContext(), 80f)
                            marginInfo.leftMargin = rectF.right - width - offset
                            marginInfo.bottomMargin = bottomMargin + rectF.height() + offset
                        }
                    }, customShape)
                    .addHighLight(R.id.yyyyy, R.layout.xxxxx, object : OnBaseCallback(offest) {
                        override fun getPosition(rightMargin: Float, bottomMargin: Float, rectF: RectF, marginInfo: HighLight.MarginInfo) {
                            marginInfo.leftMargin = rectF.right - 2 * rectF.width()
                            marginInfo.bottomMargin = bottomMargin + rectF.height() + offset
                        }
                    }, CircleLightShape())
                    .addHighLight(R.id.yyyyy, R.layout.xxxxx, OnTopPosCallback(offest), CircleLightShape())
                    /*下一步*/
                    .addHighLight(R.id.yyyyy, R.layout.xxxxx, object : OnBaseCallback(offest) {
                        override fun getPosition(rightMargin: Float, bottomMargin: Float, rectF: RectF, marginInfo: HighLight.MarginInfo) {
                            marginInfo.leftMargin = rightMargin - rectF.width() / 2
                            marginInfo.bottomMargin = bottomMargin + offset
                        }
                    }, object : BaseLightShape() {
                        override fun drawShape(bitmap: Bitmap?, viewPosInfo: HighLight.ViewPosInfo?) {

                        }

                        override fun resetRectF4Shape(viewPosInfoRectF: RectF?, dx: Float, dy: Float) {
                        }
                    })
                    .setOnLayoutCallback {
                        val hightLightView = highLight.getHightLightView()
                        hightLightView.findViewById<View>(R.id.next).setOnClickListener {
                            highLight.remove()
                            if (true) {
                                showTwoMode()
                            } else {
                                showOneMode()
                            }
                        }
                    }
                    /* .setClickCallback {
                         *//*enableNext  为true 生效*//*
                        highLight.next()
                    }*/
                    .show()
        }
    }

为节省篇幅,粘贴一处Layout

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="@dimen/dimmen_80dp"
    android:layout_height="wrap_content"
    android:layout_centerHorizontal="true"
    android:orientation="vertical"
    tools:background="@color/gray_transparent">

    <ImageView
        android:id="@+id/arrow"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:padding="@dimen/padding_5dp"
        android:src="@drawable/guide_arrow_up" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:gravity="center_horizontal"
        android:lineSpacingExtra="1.5dp"
        android:text="@string/tip_mode"
        android:textColor="@color/white"
        android:textSize="@dimen/textsize_16sp" />
</LinearLayout>


细节如下
  1. 源代码中将布局设置成layout ID 所以在xml最外层设置ID是会被这个覆盖的,这样能编译通过,但AS会报红,不影响。
    hightLightView.findViewById<View>(R.layout....)
  2. customShape自定义的高亮画布这边,直接奉上,需要注意的是使用shape较好,缩放不会出现多余部分。
    customShape->drawShape
  3. 不画高亮背景
object : BaseLightShape() {
    override fun drawShape(bitmap: Bitmap?, viewPosInfo: HighLight.ViewPosInfo?) {

      }

      override fun resetRectF4Shape(viewPosInfoRectF: RectF?, dx: Float, dy: Float) {
      }
  }
  1. 除了OnBaseCallback的四个基础子类,使用自定义的定位器OnBaseCallback,满足不同需求,
//控件 中下方 **控件不处于正中间**
object : OnBaseCallback(offest) {
	 override fun getPosition(rightMargin: Float, bottomMargin: Float, rectF: RectF, marginInfo: HighLight.MarginInfo) {
	      val width = DensityUtils.dp2px(requireContext(), 80f)
	      marginInfo.leftMargin = rectF.right - width - offset
	      marginInfo.bottomMargin = bottomMargin + rectF.height() + offset
	  }
	}
	
//控件 中上方 **控件正中间**
object : OnBaseCallback(offest) {
    override fun getPosition(rightMargin: Float, bottomMargin: Float, rectF: RectF, marginInfo: HighLight.MarginInfo) {
         marginInfo.leftMargin = rightMargin - rectF.width() / 2
         marginInfo.bottomMargin = bottomMargin + offset
     }
 }
 

//控件 左对齐 上方
object : OnBaseCallback(offest) {
     override fun getPosition(rightMargin: Float, bottomMargin: Float, rectF: RectF, marginInfo: HighLight.MarginInfo) {
         marginInfo.leftMargin = rectF.right - rectF.width() + offset * 2
         marginInfo.bottomMargin = bottomMargin + rectF.height() + offset
     }
 }
//控件 右对齐 上方
object : OnBaseCallback(offest) {
	     override fun getPosition(rightMargin: Float, bottomMargin: Float, rectF: RectF, marginInfo: HighLight.MarginInfo) {
	          val width = DensityUtils.dp2px(requireContext(), 80f)
	          marginInfo.leftMargin = rectF.right - width - offset
	          marginInfo.bottomMargin = bottomMargin + rectF.height() + offset
	      }
	  }
	  
//控件 左上方  
object : OnBaseCallback(offest) {
	      override fun getPosition(rightMargin: Float, bottomMargin: Float, rectF: RectF, marginInfo: HighLight.MarginInfo) {
	          marginInfo.leftMargin = rectF.right - 2 * rectF.width()
	          marginInfo.bottomMargin = bottomMargin + rectF.height() + offset
	      }
	  }
	  
//控件 右上方   
OnTopPosCallback(offest)
引入

implementation 'com.isanwenyu.highlight:highlight:1.8.0'

工具类如下
fun dp2pxFloat(context: Context, dpVal: Float): Float {
	return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
	         dpVal, context.resources.displayMetrics)
       }
     fun dp2px(context: Context, dpVal: Float): Int {
            return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
                    dpVal, context.resources.displayMetrics).toInt()
        }
其他

参考github:https://github.com/hongyangAndroid/Highlight

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-12-18 16:06:39  更:2021-12-18 16:06:52 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/1 1:51:40-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码