讲一些Compose里面已经被做好的手势操作

1,555 阅读8分钟

这又是一篇关于语法基础的文章,主要讲的是关于Compose里面的手势操作api怎么使用,因为在这之前,我们都用惯了传统Android里面的手势操作api,比如setOnClickListener,setOnTouchListener等等,而在Compose里面,如果不去了解下这个新的UI体系下如何去处理手势操作,一旦想要去实现一些涉及到与屏幕进行交互的功能的时候,你会发现实现起来很困难或者无从下手

点击操作

点击操作应该是使用的最频繁的操作,最常见是就是点击一个按钮来实现一段逻辑处理,比如现在屏幕上有一个按钮,我们要实现点击这个按钮然后在它的上方显示一段文案,再点击一次就把这个文案隐藏,我们一般会这样实现

image.png

有一个变量showTips,用它来控制一段文案是否显示,默认是不展示的,而在我们Button组件里面通过onClick属性就可以设置按钮的点击事件,当点击按钮时候,改变showTips的值,从而触发Composable函数重组并且再去判断是否展示文案,逻辑很简单,实现效果如下

0428aa1.gif

但是并不是所有组件都有onClick属性的,难道只能在Button上设置点击事件吗,当然不是,我们将界面上的按钮换成一个Box试试看

image.png

Box里面只有一个Modifier参数,没有onClick属性,那么我们如果想要给Box设置点击事件,只能从Modifier入手,然后的确发现它有提供一个clickable函数,这个函数里面就有一个onClick属性来处理点击事件

image.png

所以我们来改动下我们的例子,来给Box设置一个点击事件

image.png

达到的效果也是一样的

0428aa3.gif

复合点击操作

当然我们除了点击操作以外,还会经常遇到双击操作,长按操作,这两个操作连同刚才我们说的点击操作都可以使用Modifier提供的combinedClickable函数一起实现,我们看下这个函数提供的参数都有哪些

image.png

我们看到不但有onClick,还有onLongClickonDoubleClick属性,也就是combinedClickable可以同时满足这三种操作,我们将刚才的例子更改一下试试看这个函数

image.png

这次我们将文案常驻在方块上面,在蓝色方块上分别执行点击,双击以及长按操作,并且在操作之后给文案赋予不同的值,效果如下

0428aa4.gif

拖拽操作

我们在Modifier的操作符里面还能看到这样一个draggable函数,这个函数通常都是拿来进行一些简单的横向或者纵向拖拽操作的,我们看下draggable都需要传哪些参数

image.png

我们看到必传的有两个,分别是DraggableStateOrientation,后者很明显,就是定义这个拖拽具体是横向还是纵向的,而DraggableState它是要传一个拖拽状态,比如记录当前拖拽的位移,我们接下去就在蓝色小方块上实现个拖拽功能

image.png

这边使用了rememberDraggableState函数创建了一个DraggableState实例,并且实时更新offsetX值即小方块的位移,在Box里面,我们将offsetX更新到Modifier.offset函数中,并将创建好的DraggableState实例传给draggable函数,我们的拖拽功能就完成了,效果如下

0428aa5.gif

这里要注意一点的是,由于Modifier操作符的调用顺序,offset函数必须在draggable之前调用,不然拖拽是不生效的,毕竟拖拽的时候如果不知道位移,那肯定不动啊,刚刚在看draggable函数的时候,有两个参数引起了我的注意,就是onDragStartedonDragStopped,这俩参数都是挂起函数类型,并提供了一个协程作用域,也就是说能在拖拽开始和拖拽结束的时候进行一些耗时操作,比如网络请求,那么我们可以做一个类似于下拉刷新的效果出来,首先将我们的刚才的布局改一下,改成最外层是一个帧布局,里面是俩布局叠加在一起

image.png

offsetY是垂直方向上的位移,max是垂直上可以移动的最大距离,现在准备给Spacer设置一个渐变背景,并且在拖拽结束后让这个渐变背景的颜色顺序时刻发生变化并维持一段时间,我们先将渐变背景需要的颜色创建出来

image.png

reverse是一个布尔值,true的时候让colorList的顺序更改一下,false的时候再变回来,我们将这一段逻辑用来给Spacer做渐变色

image.png

现在我们在拖拽结束的地方创建一个Flow,在上游每200毫秒就在下游改变一下reverse的值,两秒钟以后让拖拽位移还原到初始位置,代码如下

image.png

最终效果如下

0429aa1.gif

滑动操作

我们使用swipeable操作符来实现组件的滑动效果,与draggable不同的是,swipeable通过设置锚点值来实现组件的吸附效果,这里就使用swipeable来实现一个开关控件,首先来看下swipeable都需要传哪些参数

image.png

可以看到必传的参数有

  • state:是一个SwipeableState,可以记录当前的偏移数据
  • anchors:锚点,用来记录不同滑动数据对应的状态
  • orientation:滑动方向
  • thresholds:不同锚点之间的临界值

知道了需要的参数,那我们现在将它们逐个创建出来

image.png

首先创建滑块大小,要用它来计算我们整个控件的大小,还有状态间的切换,然后再创建个SwipeableState,并且设置初始值为start,然后再是我们的锚点,是一个map,并且定义两种滑动距离所对应的状态,滑块布局的代码如下

image.png

布局就是两个Box之间的嵌套,里面的Box就是我们的滑块,我们的滑块里面就使用了swipeable操作符,除了设置了刚刚设置的SwipeableState与锚点,还设置了临界值threholds,当前状态如果是start,也就是滑块在左边的时候,滑动距离在整个父布局的百分之三十以内都属于start状态,也就是如果松手了,滑块会自动吸附值0f的位置,反之,如果滑块的end状态,如果滑动距离不超过百分之五十,如果松手之后,滑块又回自动吸附值布局最右边,我们看下效果是不是这样

0430aa1.gif

多点触控

在日常生活当中,多点触控这样的操作多数是在浏览图片,网页或者地图之类的场景下被用到,而在Compose中,多点触控是通过transformable操作符来实现,我们看下使用transformable需要哪些参数

image.png

我们看到只有一个必传参数TransformableState,这个是用来获取多点触控时候目标组件大小,位移,旋转角度变化情况的,我们可以使用它来实现对一张图片进行双指拖动,缩放和旋转事件

image.png

首先我们创建三个变量,分别表示图片的位移,旋转角度以及大小,然后我们创建一个Transformable实时更新这三个变量的值

image.png

我们使用rememberTransformableState函数创建了一个TransformableState对象,现在可以将这三个变量赋值给我们的图片了,代码如下

image.png

我们看到了分别将刚刚创建的三个变量带入到了rotate,offset,scale函数里去,这里的顺序要注意一下,offset不要比rotate调用的早,这会导致旋转后的最终位置不可预期,我们看下效果

0501aa1.gif

刚刚我们在看transformable函数的参数的时候,还有个参数是lockRotationOnZoomPan,默认值是false,这个是干嘛的呢?注释上有解释,这个参数的意思是如果设置为false,那么多点触控的时候将会同时监听双指拖动,缩放以及旋转,但是如果设置为true的时候,除非旋转动作比其余两个动作先执行,这样会被监听到,不然的话,只会监听双指拖动和缩放动作,旋转事件将不会被监听,我们来试一下,将上述代码的lockRotationOnZoomPan设置为true

image.png

再来看下效果如何

0501aa2.gif

我们看到了这次先进行缩放动作,这个时候无论怎么再去转动图片,图片也都不会再改变旋转角度了,这也刚好满足图片预览的需求,毕竟预览图片时候也都不需要去旋转图片

总结

通过这篇文章对这几个关于手势操作的函数的了解,以后再去处理一些简单的手势操作需求就会变得更加得心应手,这里讲到的这些手势操作是已经被封装好的,虽然用起来方便,但是可以实现的需求范围有限,下一篇会讲到更加底层的一些手势操作api