Android侧滑栏(一)可缩放可一起移动的侧滑栏

这篇具有很好参考价值的文章主要介绍了Android侧滑栏(一)可缩放可一起移动的侧滑栏。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

在实际的各类App开发中,经常会需要做一个左侧的侧滑栏,类似于QQ这种。

今天这篇文章总结下自己在开发中遇到的这类可以跟随移动且可以缩放的侧滑栏。

一、实现原理

使用 HorizontalScrollView 实现一个水平方向的可滑动的View,左布局为侧滑栏,右布局为自己的主页内容。

来看下android的官方解释,我用谷歌翻译了:

用户可以滚动的视图层次结构的布局容器,允许其大于物理显示。 HorizontalScrollView 是一种 FrameLayout,这意味着您应该在其中放置一个包含要滚动的全部内容的子级;这个子级本身可能是一个具有复杂对象层次结构的布局管理器。经常使用的子级是水平方向的 LinearLayout,它呈现用户可以滚动的顶级项目的水平数组。
TextView 类还负责自己的滚动,因此不需要 HorizontalScrollView,但将两者结合使用可以在更大的容器中实现文本视图的效果。
HorizontalScrollView 仅支持水平滚动。对于垂直滚动,请使用 ScrollView 或 ListView。
属性

关键点:

1、用户可以滚动的视图层次结构的布局容器,允许其大于物理显示。证明就像我们平时的用到的垂直方向的scrollView嵌套几个列表一样。

2、HorizontalScrollView 是一种 FrameLayout,这意味着您应该在其中放置一个包含要滚动的全部内容的子级;这个代表你需要在HorizontalScrollView先放一个总布局,再在这个布局里放左右布局内容。

二、实现过程

第一步:xml布局

<?xml version="1.0" encoding="utf-8"?>
    <wanwan.and.lx.lxslideviewdemo.SlideMenuLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/sliding"
        android:background="@mipmap/img_bg"
        tools:context=".MainActivity">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="horizontal">
            <LinearLayout
                android:layout_width="200dp"
                android:layout_height="match_parent"
                android:layout_gravity="start"
                android:orientation="vertical"
                >

                <RelativeLayout
                    android:id="@+id/sidebarLayout"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent">

                    <androidx.appcompat.widget.AppCompatImageView
                        android:id="@+id/sidebar_image_app_icon"
                        android:layout_width="80dp"
                        android:layout_height="80dp"
                        android:layout_centerHorizontal="true"
                        android:layout_marginTop="106dp"
                        android:scaleType="fitXY"
                        android:src="@mipmap/ic_launcher" />

                    <androidx.constraintlayout.widget.ConstraintLayout
                        android:id="@+id/slide_item_privacy"
                        android:layout_width="200dp"
                        android:layout_height="57dp"
                        android:layout_below="@id/sidebar_image_app_icon"
                        android:layout_marginTop="30dp">

                        <androidx.appcompat.widget.AppCompatImageView
                            android:id="@+id/set_privacy_lock_img"
                            android:layout_width="16dp"
                            android:layout_height="16dp"
                            android:layout_marginStart="32dp"
                            android:src="@mipmap/privacy"
                            app:layout_constraintBottom_toBottomOf="parent"
                            app:layout_constraintStart_toStartOf="parent"
                            app:layout_constraintTop_toTopOf="parent" />

                        <androidx.appcompat.widget.AppCompatTextView
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:layout_marginStart="13.7dp"
                            android:text="Privacy Policy"
                            android:textColor="@color/black"
                            android:textSize="17sp"
                            app:layout_constraintBottom_toBottomOf="parent"
                            app:layout_constraintStart_toEndOf="@id/set_privacy_lock_img"
                            app:layout_constraintTop_toTopOf="parent" />

                    </androidx.constraintlayout.widget.ConstraintLayout>

                    <androidx.constraintlayout.widget.ConstraintLayout
                        android:id="@+id/slide_item_share"
                        android:layout_width="200dp"
                        android:layout_height="57dp"
                        android:layout_below="@id/slide_item_privacy"
                        android:layout_marginTop="10dp">

                        <androidx.appcompat.widget.AppCompatImageView
                            android:id="@+id/set_share_lock_img"
                            android:layout_width="16dp"
                            android:layout_height="16dp"
                            android:layout_marginStart="32dp"
                            android:src="@mipmap/share"
                            app:layout_constraintBottom_toBottomOf="parent"
                            app:layout_constraintStart_toStartOf="parent"
                            app:layout_constraintTop_toTopOf="parent" />

                        <androidx.appcompat.widget.AppCompatTextView
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:layout_marginStart="13.7dp"
                            android:text="Share"
                            android:textColor="@color/black"
                            android:textSize="17sp"
                            app:layout_constraintBottom_toBottomOf="parent"
                            app:layout_constraintStart_toEndOf="@id/set_share_lock_img"
                            app:layout_constraintTop_toTopOf="parent" />

                    </androidx.constraintlayout.widget.ConstraintLayout>

                    <androidx.constraintlayout.widget.ConstraintLayout
                        android:id="@+id/slide_item_update"
                        android:layout_width="200dp"
                        android:layout_height="57dp"
                        android:layout_below="@id/slide_item_share"
                        android:layout_marginTop="10dp">

                        <androidx.appcompat.widget.AppCompatImageView
                            android:id="@+id/set_update_lock_img"
                            android:layout_width="16dp"
                            android:layout_height="16dp"
                            android:layout_marginStart="32dp"
                            android:src="@mipmap/update"
                            app:layout_constraintBottom_toBottomOf="parent"
                            app:layout_constraintStart_toStartOf="parent"
                            app:layout_constraintTop_toTopOf="parent" />

                        <androidx.appcompat.widget.AppCompatTextView
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:layout_marginStart="13.7dp"
                            android:text="Update"
                            android:textColor="@color/black"
                            android:textSize="17sp"
                            app:layout_constraintBottom_toBottomOf="parent"
                            app:layout_constraintStart_toEndOf="@id/set_update_lock_img"
                            app:layout_constraintTop_toTopOf="parent" />

                    </androidx.constraintlayout.widget.ConstraintLayout>

                </RelativeLayout>
            </LinearLayout>
            <RelativeLayout
                android:layout_width="match_parent"
                android:background="@color/white"
                android:layout_height="match_parent">
                <androidx.appcompat.widget.AppCompatTextView
                    android:id="@+id/text"
                    android:layout_width="wrap_content"
                    android:layout_centerInParent="true"
                    android:textStyle="bold"
                    android:textSize="18sp"
                    android:textColor="@color/black"
                    android:layout_height="wrap_content"
                    android:text="这是主页"/>

                <androidx.appcompat.widget.AppCompatImageView
                    android:layout_marginTop="20dp"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:src="@mipmap/set"
                    android:layout_centerHorizontal="true"
                    android:layout_below="@id/text"
                    android:id="@+id/set"/>
            </RelativeLayout>
        </LinearLayout>
    </wanwan.and.lx.lxslideviewdemo.SlideMenuLayout>

1.SlideMenuLayout其实就是HorizontalScrollView,这是个自定义控件,待会儿代码附上。

2.可以看到SlideMenuLayout只有一个子View,为LinearLayout,LinearLayout它是全屏且水平布局,且有两个子布局,分为左右。

第二步:自定义控件HorizontalScrollView

class SlideMenuLayout : HorizontalScrollView {
    /**
     * 当菜单页显示时,右侧内容页显示宽度
     */
    private var menuRightWidth = 0
    
    private lateinit var menuView: View
    
    private lateinit var contentView: View
    
    /**
     * 用于处理飞速滑动
     */
    private var gestureDetector: GestureDetector
  
    var isMenuOpen: Boolean = false
    
    private var btn: AppCompatImageView? = null
    /**
     * 是否进行事件拦截
     */
    private var isIntercept = false

    constructor(context: Context) : this(context, null)
    constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
        context, attrs, defStyleAttr
    ) {
        gestureDetector = GestureDetector(getContext(), GestureDetectorListener())
    }

    //用于处理飞速滑动
    inner class GestureDetectorListener : SimpleOnGestureListener() {
        override fun onFling(
            e1: MotionEvent, e2: MotionEvent, velocityX: Float, velocityY: Float
        ): Boolean {
            //屏蔽向右滑动
            if (e2.x - e1.x > 30) {
                Log.e("TAG", "right, right, go go go --->")
                return true
            }
            if (abs(velocityY) > abs(velocityX)) {
                return false
            }
            if (isMenuOpen) {
                if (velocityX < 0) {
                    closeMenu()
                    return true
                }
            } else {
                if (velocityX > 0) {
                    openMenu()
                    return true
                }
            }
            return super.onFling(e1, e2, velocityX, velocityY)

        }
    }

    /**
     * 此方法在布局加载完毕时调用
     */
    override fun onFinishInflate() {
        super.onFinishInflate()
        val linearLayout: LinearLayout = getChildAt(0) as LinearLayout
        val childCount = linearLayout.childCount
        if (childCount != 2) {
            throw IllegalArgumentException("LinearLayout child size must be 2!")
        }
        menuView = linearLayout.getChildAt(0)
        val menuLayoutParams = menuView.layoutParams
        menuLayoutParams.width = getScreenWidth() - menuRightWidth - SizeUtils.dp2px(100f)
        menuView.layoutParams = menuLayoutParams

        //设置右侧内容页宽度为屏幕宽度
        contentView = linearLayout.getChildAt(1)
        linearLayout.removeView(contentView)
        val contentRelativeLayout = RelativeLayout(context)
        contentRelativeLayout.addView(contentView)
        val contentLayoutParams = contentView.layoutParams
        contentLayoutParams.width = getScreenWidth()
        contentRelativeLayout.layoutParams = contentLayoutParams
        linearLayout.addView(contentRelativeLayout)
        
        btn = contentView.findViewById(R.id.set)
        btn?.setOnClickListener {
            openMenu()
        }
    }


    override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
        super.onLayout(changed, l, t, r, b)
        //默认情况下,应该全部展示内容页,关闭左侧菜单页
        scrollTo(menuView.measuredWidth, 0)
    }


    /**
     * 获取当前屏幕的宽度
     */
    private fun getScreenWidth(): Int {
        return resources.displayMetrics.widthPixels
    }


    /**
     * 重写该方法,用于处理缩放和透明度效果
     */
    override fun onScrollChanged(l: Int, t: Int, oldl: Int, oldt: Int) {
        super.onScrollChanged(l, t, oldl, oldt)
        //滚动的时候,不停的回调  l 从屏幕宽度变化到 0
        val scale = 1 - l * 1f / menuView.measuredWidth //scale 从 0 到1
        //处理菜单页缩放和透明度
        menuView.pivotX = menuView.measuredWidth * 1f
        menuView.pivotY = menuView.measuredHeight / 2f
        menuView.scaleX = 0.5f + scale * 0.5f
        menuView.scaleY = 0.5f + scale * 0.5f

        menuView.alpha = 0.25f + 0.75f * scale

        //处理内容页缩放 缩放到0.7f
        contentView.pivotX = 0f
        contentView.pivotY = contentView.measuredHeight / 2f
        contentView.scaleX = 0.7f + (1 - scale) * 0.3f
        contentView.scaleY = 0.7f + (1 - scale) * 0.3f

    }

    override fun onInterceptTouchEvent(ev: MotionEvent): Boolean {
        if (ev.action == MotionEvent.ACTION_MOVE) {
            return false
        }
        if (isMenuOpen) {
            //如果点击事件落在内容页,则进行拦截并关闭菜单页
            if (ev.x > menuView.measuredWidth) {
                //进行事件拦截,不触发button点击事件
                isIntercept = true
                return true
            } else {
                isIntercept = false
            }

        }
        return super.onInterceptTouchEvent(ev)
    }

    override fun onTouchEvent(ev: MotionEvent): Boolean {
        //当执行快速滑动时,后续不再执行
        if (ev.action == MotionEvent.ACTION_MOVE) {
            return false
        }
        if (gestureDetector.onTouchEvent(ev)) {
            return gestureDetector.onTouchEvent(ev)
        }
        when (ev.action) {
            MotionEvent.ACTION_UP -> {
                if (isIntercept) {
                    closeMenu()
                    return true
                }
                //当手指抬起时,判断左侧菜单栏应该展示开始关闭
                //判断逻辑:当滚动x > 屏幕一半是,菜单栏隐藏,否则展开
//                if (mScrollX > getScreenWidth() / 2) {
//                    closeMenu()
//                } else {
//                    openMenu()
//                }
//                return false
            }
        }
        return super.onTouchEvent(ev)
    }

    /**
     * 打开菜单
     */
    fun openMenu() {
        smoothScrollTo(0, 0)
        isMenuOpen = true
    }

    override fun dispatchTouchEvent(me: MotionEvent?): Boolean {
        if (me != null) {
            this.gestureDetector.onTouchEvent(me)
        }
        return super.dispatchTouchEvent(me)
    }

    /**
     * 关闭菜单
     */
    fun closeMenu() {
        smoothScrollTo(menuView.measuredWidth, 0)
        isMenuOpen = false
    }


}

关键点:

1、所谓的控制左右滑动,用到的是 smoothScrollTo()方法

2、使用SimpleOnGestureListener来进行手势监听,并且把onTouchEvent和dispatchTouchEvent的部分事件交由其处理。使用重写的onFling方法,进行各类手势处理,由于需求原因,上面的代码我禁止掉了右滑,可根据自己实际需求进行开发。

3、使用onInterceptTouchEvent拦截部分事件。

4、重写onScrollChanged监听滑动时,对左右布局进行缩放,这样会显得更流畅些。

5、重写onFinishInflate方法,拿到左右子布局,对其设置layoutparam属性,点击事件,赋值等等。

tips:menuLayoutParams.width = getScreenWidth() - menuRightWidth - SizeUtils.dp2px(100f)

这个就是设置左侧侧滑栏宽度,因为一般都不会全屏,所以会拿屏幕宽度去减去自己想要的值来展示右侧主页的内容,这儿可以给menuRightWidth设定一个值,不过我需求固定了,就直接在这儿减去了SizeUtils.dp2px(100f)。

第三步:代码调用:

class MainActivity : AppCompatActivity() {

    private var setImg: AppCompatImageView? = null
    private var sliding: SlideMenuLayout? = null
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        setImg = findViewById(R.id.set)
        sliding = findViewById(R.id.sliding)
        setImg?.setOnClickListener {
            sliding?.openMenu()
        }
    }
}

代码全在这儿了,我就不贴github地址了。

三、实现效果

Android侧滑栏(一)可缩放可一起移动的侧滑栏,Android UI,Android开发小功能点,android

 文章来源地址https://www.toymoban.com/news/detail-642624.html

到了这里,关于Android侧滑栏(一)可缩放可一起移动的侧滑栏的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • PyQt5实现UI自适应屏幕大小且可缩放

    PyQt5实现UI自适应屏幕大小且可缩放 在开发GUI界面的过程中,为了让用户能够在不同尺寸屏幕下都有好的体验,我们需要实现UI自适应屏幕大小的功能。而PyQt5提供了很多方法和工具来达到这个目的。 下面是一个简单的例子,展示如何使用PyQt5来实现UI自适应屏幕大小的功能:

    2024年01月16日
    浏览(27)
  • Android自定义侧滑Item

    源码地址:https://github.com/LanSeLianMa/CustomizeView/tree/master/cehuaitem 先定义一个容器

    2024年02月13日
    浏览(25)
  • Android 之 DrawerLayout (官方侧滑菜单)的简单使用

    本节给大家带来基础UI控件部分的最后一个控件: DrawerLayout ,官方给我们提供的一个侧滑菜单 控件,和上一节的ViewPager一样,3.0以后引入,低版本使用它,需要v4兼容包,说到侧滑,相信 很多人都用过github上的SlidingMenu,不过好像有两个版本,一个是单独的,另一个需要依赖

    2024年02月03日
    浏览(24)
  • vue + element-ui 穿梭框+上下移动、置顶置底功能

    预览效果:  代码 :

    2024年02月11日
    浏览(39)
  • 移动端开发常用的一些UI 组件库

    1、Vant 是一个 轻量、可靠的移动端组件库 ,于 2017 年开源。 目前 Vant 官方提供了 Vue 2 版本、Vue 3 版本和微信小程序版本,并由社区团队维护 React 版本和支付宝小程序版本。 2、VUX(读音 [v’ju:z],同 views)是基于WeUI和Vue(2.x)开发的移动端UI组件库,主要服务于微信页面。缺

    2024年02月13日
    浏览(32)
  • MAC M1 Pro搭建移动端UI自动化测试环境--Android篇

    目前大家熟知的测试主要分为功能测试、接口测试、UI测试,本文重点介绍的则是UI测试 UI 测试 通常分为WEB 端和 移动端,前者主要是针对PC端的网站进行测试,主要是模拟各个浏览器的内核的兼容性,后者则是针对App Native、H5、Hybrid进行模拟测试,发现多机型的兼容性问题

    2023年04月22日
    浏览(29)
  • 手机移动开发技术,,Android开发经典实战

    面试题库 按照系统分类 按照大厂分类 《2017-2020字节跳动Android面试真题解析》 大神手写整理笔记类 《Android框架体系架构》 书籍类 不需要太多,精就好! 《第一行代码第二版》 技能提升资料库 一共十个专题,包括了Android进阶所有学习资料,Android进阶视频,Flutter,java基础

    2024年04月13日
    浏览(33)
  • 【Android开发】移动程序设计复习大纲

    一、 判断题 (共10小题,每题1分,共10分) 二、 单选题 (共10小题,每题1分,共10分) 三、 填空题 (共10小题,每空1分,共10分) 四、 简答题 (共4小题,每题10分,共40分) 五、 程序设计题 (共2小题,每空2分,共30分) 知识点: 1. Android 体系结构包含的层次及各层的特点。

    2024年02月01日
    浏览(36)
  • Android移动应用开发的学习路线

    Android移动应用开发的学习路线。以下是一个基本的学习路线,供你参考: 1. Java基础 学习Java的基本语法和面向对象编程(OOP)的概念 了解Java的数据类型、变量和常量 学习控制结构(如条件语句、循环语句)和函数 2. Android基础 了解Android平台的基本概念和架构 学习Android的

    2024年02月11日
    浏览(36)
  • 移动应用开发环境搭建Android Studio

    记得提前开启电脑虚拟化支持,具体方法可自行百度 查看是否启用虚拟化 JDK安装与卸载 由于Andriod开发使用的语言是javaKotlin,这里使用的是java语言所以需要先安装java的开发环境 所有开发 Android 应用程序需要的工具都是开源的,并且可以从互联网上下载 Android Studio 是谷歌推

    2023年04月08日
    浏览(58)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包