这又是一篇关于语法基础的文章,主要讲的是关于Compose里面的手势操作api怎么使用,因为在这之前,我们都用惯了传统Android里面的手势操作api,比如setOnClickListener
,setOnTouchListener
等等,而在Compose里面,如果不去了解下这个新的UI体系下如何去处理手势操作,一旦想要去实现一些涉及到与屏幕进行交互的功能的时候,你会发现实现起来很困难或者无从下手
点击操作
点击操作应该是使用的最频繁的操作,最常见是就是点击一个按钮来实现一段逻辑处理,比如现在屏幕上有一个按钮,我们要实现点击这个按钮然后在它的上方显示一段文案,再点击一次就把这个文案隐藏,我们一般会这样实现
有一个变量showTips
,用它来控制一段文案是否显示,默认是不展示的,而在我们Button
组件里面通过onClick
属性就可以设置按钮的点击事件,当点击按钮时候,改变showTips
的值,从而触发Composable函数重组并且再去判断是否展示文案,逻辑很简单,实现效果如下
但是并不是所有组件都有onClick属性的,难道只能在Button上设置点击事件吗,当然不是,我们将界面上的按钮换成一个Box
试试看
Box
里面只有一个Modifier
参数,没有onClick
属性,那么我们如果想要给Box
设置点击事件,只能从Modifier
入手,然后的确发现它有提供一个clickable
函数,这个函数里面就有一个onClick
属性来处理点击事件
所以我们来改动下我们的例子,来给Box
设置一个点击事件
达到的效果也是一样的
复合点击操作
当然我们除了点击操作以外,还会经常遇到双击操作,长按操作,这两个操作连同刚才我们说的点击操作都可以使用Modifier
提供的combinedClickable
函数一起实现,我们看下这个函数提供的参数都有哪些
我们看到不但有onClick
,还有onLongClick
和onDoubleClick
属性,也就是combinedClickable
可以同时满足这三种操作,我们将刚才的例子更改一下试试看这个函数
这次我们将文案常驻在方块上面,在蓝色方块上分别执行点击,双击以及长按操作,并且在操作之后给文案赋予不同的值,效果如下
拖拽操作
我们在Modifier的操作符里面还能看到这样一个draggable
函数,这个函数通常都是拿来进行一些简单的横向或者纵向拖拽操作的,我们看下draggable
都需要传哪些参数
我们看到必传的有两个,分别是DraggableState
和Orientation
,后者很明显,就是定义这个拖拽具体是横向还是纵向的,而DraggableState
它是要传一个拖拽状态,比如记录当前拖拽的位移,我们接下去就在蓝色小方块上实现个拖拽功能
这边使用了rememberDraggableState
函数创建了一个DraggableState
实例,并且实时更新offsetX
值即小方块的位移,在Box
里面,我们将offsetX
更新到Modifier.offset
函数中,并将创建好的DraggableState
实例传给draggable
函数,我们的拖拽功能就完成了,效果如下
这里要注意一点的是,由于Modifier
操作符的调用顺序,offset
函数必须在draggable
之前调用,不然拖拽是不生效的,毕竟拖拽的时候如果不知道位移,那肯定不动啊,刚刚在看draggable
函数的时候,有两个参数引起了我的注意,就是onDragStarted
和onDragStopped
,这俩参数都是挂起函数类型,并提供了一个协程作用域,也就是说能在拖拽开始和拖拽结束的时候进行一些耗时操作,比如网络请求,那么我们可以做一个类似于下拉刷新的效果出来,首先将我们的刚才的布局改一下,改成最外层是一个帧布局,里面是俩布局叠加在一起
offsetY
是垂直方向上的位移,max
是垂直上可以移动的最大距离,现在准备给Spacer设置一个渐变背景,并且在拖拽结束后让这个渐变背景的颜色顺序时刻发生变化并维持一段时间,我们先将渐变背景需要的颜色创建出来
reverse
是一个布尔值,true的时候让colorList
的顺序更改一下,false的时候再变回来,我们将这一段逻辑用来给Spacer
做渐变色
现在我们在拖拽结束的地方创建一个Flow
,在上游每200毫秒就在下游改变一下reverse
的值,两秒钟以后让拖拽位移还原到初始位置,代码如下
最终效果如下
滑动操作
我们使用swipeable
操作符来实现组件的滑动效果,与draggable
不同的是,swipeable
通过设置锚点值来实现组件的吸附效果,这里就使用swipeable
来实现一个开关控件,首先来看下swipeable
都需要传哪些参数
可以看到必传的参数有
- state:是一个SwipeableState,可以记录当前的偏移数据
- anchors:锚点,用来记录不同滑动数据对应的状态
- orientation:滑动方向
- thresholds:不同锚点之间的临界值
知道了需要的参数,那我们现在将它们逐个创建出来
首先创建滑块大小,要用它来计算我们整个控件的大小,还有状态间的切换,然后再创建个SwipeableState
,并且设置初始值为start
,然后再是我们的锚点,是一个map
,并且定义两种滑动距离所对应的状态,滑块布局的代码如下
布局就是两个Box
之间的嵌套,里面的Box就是我们的滑块,我们的滑块里面就使用了swipeable
操作符,除了设置了刚刚设置的SwipeableState
与锚点,还设置了临界值threholds
,当前状态如果是start
,也就是滑块在左边的时候,滑动距离在整个父布局的百分之三十以内都属于start
状态,也就是如果松手了,滑块会自动吸附值0f的位置,反之,如果滑块的end
状态,如果滑动距离不超过百分之五十,如果松手之后,滑块又回自动吸附值布局最右边,我们看下效果是不是这样
多点触控
在日常生活当中,多点触控这样的操作多数是在浏览图片,网页或者地图之类的场景下被用到,而在Compose中,多点触控是通过transformable
操作符来实现,我们看下使用transformable
需要哪些参数
我们看到只有一个必传参数TransformableState
,这个是用来获取多点触控时候目标组件大小,位移,旋转角度变化情况的,我们可以使用它来实现对一张图片进行双指拖动,缩放和旋转事件
首先我们创建三个变量,分别表示图片的位移,旋转角度以及大小,然后我们创建一个Transformable
实时更新这三个变量的值
我们使用rememberTransformableState
函数创建了一个TransformableState
对象,现在可以将这三个变量赋值给我们的图片了,代码如下
我们看到了分别将刚刚创建的三个变量带入到了rotate
,offset
,scale
函数里去,这里的顺序要注意一下,offset
不要比rotate
调用的早,这会导致旋转后的最终位置不可预期,我们看下效果
刚刚我们在看transformable
函数的参数的时候,还有个参数是lockRotationOnZoomPan
,默认值是false
,这个是干嘛的呢?注释上有解释,这个参数的意思是如果设置为false
,那么多点触控的时候将会同时监听双指拖动,缩放以及旋转,但是如果设置为true
的时候,除非旋转动作比其余两个动作先执行,这样会被监听到,不然的话,只会监听双指拖动和缩放动作,旋转事件将不会被监听,我们来试一下,将上述代码的lockRotationOnZoomPan
设置为true
再来看下效果如何
我们看到了这次先进行缩放动作,这个时候无论怎么再去转动图片,图片也都不会再改变旋转角度了,这也刚好满足图片预览的需求,毕竟预览图片时候也都不需要去旋转图片
总结
通过这篇文章对这几个关于手势操作的函数的了解,以后再去处理一些简单的手势操作需求就会变得更加得心应手,这里讲到的这些手势操作是已经被封装好的,虽然用起来方便,但是可以实现的需求范围有限,下一篇会讲到更加底层的一些手势操作api