任丘做网站价格,0基础学网站建设,微信小程序赚钱,餐饮设计网站View 的滑动是 Android 实现自定义控件的基础#xff0c;同时在开发中我们也难免会遇到 View 的滑动处理。其实不管是哪种滑动方式#xff0c;其基本思想都是类似的#xff1a;当点击事件传到 View 时#xff0c;系统记下触摸点的坐标#xff0c;手指移动时系统记下移动后… View 的滑动是 Android 实现自定义控件的基础同时在开发中我们也难免会遇到 View 的滑动处理。其实不管是哪种滑动方式其基本思想都是类似的当点击事件传到 View 时系统记下触摸点的坐标手指移动时系统记下移动后触摸的坐标并算出偏移量并通过偏移量来修改View的坐标。 实现 View 滑动有很多种方法在这里主要讲解6种滑动方法分别是 layout()、offsetLeftAndRight() 与 offsetTopAndBottom()、LayoutParams、Animation、scollTo() 与 scollBy()以及 Scroller。
一、layout() 方法
View 进行绘制的时候会调用 onLayout() 方法来设置显示的位置因此我们同样也可以通过修改 View 的 left、top、right、bottom 这4种属性来控制 View 的坐标。首先我们要自定义一个 View在 onTouchEvent() 方法中获取触摸点的坐标代码如下所示
override fun onTouchEvent(event: MotionEvent?): Boolean {// 获取手指触摸点的横坐标和纵坐标val x event?.x?.toInt()val y event?.y?.toInt()when (event?.action) {MotionEvent.ACTION_DOWN - {lastX x ?: 0lastY y ?: 0}...}...
}接下来我们在 ACTION_MOVE 事件中计算偏移量再调用 layout() 方法重新放置这个自定义 View 的位置即可。
override fun onTouchEvent(event: MotionEvent?): Boolean {...when (event?.action) {...MotionEvent.ACTION_MOVE - {// 计算移动的距离val offsetX x ?: (0 - lastX)val offsetY y ?: (0 - lastY)// 调用 layout 方法来重新放置它的位置layout(left offsetX, top offsetY, right offsetX, bottom offsetY)}}...
}在每次移动时都会调用 layout() 方法对屏幕重新布局从而达到移动 View 的效果。自定义 View 的全部代码如下所示
class CustomView(context: Context, attributeSet: AttributeSet) : View(context, attributeSet) {private var lastX 0private var lastY 0override fun onTouchEvent(event: MotionEvent?): Boolean {// 获取手指触摸点的横坐标和纵坐标val x event?.x?.toInt()val y event?.y?.toInt()when (event?.action) {MotionEvent.ACTION_DOWN - {lastX x ?: 0lastY y ?: 0}MotionEvent.ACTION_MOVE - {// 计算移动的距离val offsetX x ?: (0 - lastX)val offsetY y ?: (0 - lastY)// 调用 layout 方法来重新放置它的位置layout(left offsetX, top offsetY, right offsetX, bottom offsetY)}}return true}
}随后我们在布局中引用自定义 View 就可以了
com.tyhoo.android.demo.CustomViewandroid:idid/test_viewandroid:layout_width100dpandroid:layout_height100dpandroid:backgroundandroid:color/holo_red_light... /运行程序效果如图1所示 图1 图1中的方块就是我们自定义的 View它会随着我们手指的滑动改变自己的位置。
二、offsetLeftAndRight() 与 offsetTopAndBottom()
这两种方法和 layout() 方法的效果差不多其使用方式也差不多。我们将 ACTION_MOVE 中的代码替换成如下代码
override fun onTouchEvent(event: MotionEvent?): Boolean {...when (event?.action) {...MotionEvent.ACTION_MOVE - {// 计算移动的距离val offsetX x ?: (0 - lastX)val offsetY y ?: (0 - lastY)// 对 left 和 right 进行偏移offsetLeftAndRight(offsetX)// 对 top 和 bottom 进行偏移offsetTopAndBottom(offsetY)}}...
}三、LayoutParams
LayoutParams 主要保存了一个 View 的布局参数因此我们可以通过 LayoutParams 来改变 View 的布局参数从而达到改变 View 位置的效果。同样我们将 ACTION_MOVE 中的代码替换成如下代码
override fun onTouchEvent(event: MotionEvent?): Boolean {...when (event?.action) {...MotionEvent.ACTION_MOVE - {// 计算移动的距离val offsetX x ?: (0 - lastX)val offsetY y ?: (0 - lastY)val layoutParams layoutParams as ConstraintLayout.LayoutParamslayoutParams.leftMargin left offsetXlayoutParams.topMargin top offsetYsetLayoutParams(layoutParams)}}...
}因为父控件是 ConstraintLayout所以我们用了 ConstraintLayout.LayoutParams。如果父控件是 RelativeLayout则要使用RelativeLayout.LayoutParams。除了使用布局的 LayoutParams 外我们还可以用 ViewGroup.MarginLayoutParams 来实现
override fun onTouchEvent(event: MotionEvent?): Boolean {...when (event?.action) {...MotionEvent.ACTION_MOVE - {// 计算移动的距离val offsetX x ?: (0 - lastX)val offsetY y ?: (0 - lastY)val layoutParams layoutParams as ViewGroup.MarginLayoutParamslayoutParams.leftMargin left offsetXlayoutParams.topMargin top offsetYsetLayoutParams(layoutParams)}}...
}四、Animation
可以采用 View 动画来移动在 res 目录新建 anim 文件夹并创建 translate.xml
?xml version1.0 encodingutf-8?
set xmlns:androidhttp://schemas.android.com/apk/res/androidtranslateandroid:duration1000android:fromXDelta0android:toXDelta300 /
/set接下来在 Kotlin 代码中调用就好了代码如下所示
class MainActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)val testView findViewByIdCustomView(R.id.test_view)testView.animation AnimationUtils.loadAnimation(this, R.anim.translate)}
}运行程序效果如图2所示 图2 运行程序我们设置的方块会向右平移300像素然后又会回到原来的位置。为了解决这个问题我们需要在 translate.xml 中加上 fillAfter“true”代码如下所示
?xml version1.0 encodingutf-8?
set xmlns:androidhttp://schemas.android.com/apk/res/androidandroid:fillAftertruetranslateandroid:duration1000android:fromXDelta0android:toXDelta300 /
/set运行程序效果如图3所示 图3 运行代码后会发现方块向右平移300像素后就停留在当前位置了。
需要注意的是View 动画并不能改变 View 的位置参数。如果对一个 View 进行如上的平移动画操作当 View 平移300像素停留在当前位置时我们点击这个 View 并不会触发点击事件但在我们点击这个 View 的原始位置时却触发了点击事件。对于系统来说这个 View 并没有改变原有的位置所以我们点击其他位置当然不会触发这个 View 的点击事件。
五、scrollTo() 与 scollBy()
scrollTo(x, y) 表示移动到一个具体的坐标点而 scrollBy(dx, dy) 则表示移动的增量为 dx、dy。其中scollBy 最终也是要调用 scollTo 的。View 的 scollTo 和 scollBy 的源码如下所示
public void scrollTo(int x, int y) {if (mScrollX ! x || mScrollY ! y) {int oldX mScrollX;int oldY mScrollY;mScrollX x;mScrollY y;invalidateParentCaches();onScrollChanged(mScrollX, mScrollY, oldX, oldY);if (!awakenScrollBars()) {postInvalidateOnAnimation();}}
}public void scrollBy(int x, int y) {scrollTo(mScrollX x, mScrollY y);
}scollTo、scollBy 移动的是 View 的内容如果在 ViewGroup 中使用则是移动其所有的子 View。我们将 ACTION_MOVE 中的代码替换成如下代码
override fun onTouchEvent(event: MotionEvent?): Boolean {...when (event?.action) {...MotionEvent.ACTION_MOVE - {// 计算移动的距离val offsetX x ?: (0 - lastX)val offsetY y ?: (0 - lastY)(parent as View).scrollBy(-offsetX, -offsetY)}}return true
}这里若要实现自定义 View 随手指移动的效果就需要将偏移量设置为负值。为什么要设置为负值呢这是参考对象不同导致的差异。所以我们用 scrollBy 方法的时候要设置负数才会达到自己想要的效果。
六、Scroller
我们在用 scollTo/scollBy 方法进行滑动时这个过程是瞬间完成的所以用户体验不大好。这里我们可以使用 Scroller 来实现有过渡效果的滑动这个过程不是瞬间完成的而是在一定的时间间隔内完成的。Scroller 本身是不能实现 View 的滑动的它需要与 View 的 computeScroll() 方法配合才能实现弹性滑动的效果。在这里我们实现自定义 View 平滑地向右移动。首先我们要初始化 Scroller代码如下所示
class CustomView(context: Context, attributeSet: AttributeSet) : View(context, attributeSet) {...private var scroller: Scroller? nullinit {scroller Scroller(context)}...
}接下来重写 computeScroll() 方法系统会在绘制 View 的时候在 draw() 方法中调用该方法。在这个方法中我们调用父类的 scrollTo() 方法并通过 Scroller 来不断获取当前的滚动值每滑动一小段距离我们就调用invalidate() 方法不断地进行重绘重绘就会调用 computeScroll() 方法这样我们通过不断地移动一个小的距离并连贯起来就实现了平滑移动的效果。
override fun computeScroll() {super.computeScroll()scroller?.let {if (it.computeScrollOffset()) {(parent as View).scrollTo(it.currX, it.currY)invalidate()}}
}我们在自定义 View 中写一个 smoothScrollTo 方法调用 Scroller 的 startScroll() 方法在 2000ms 内沿 X 轴平移 delta 像素代码如下所示
fun smoothScrollTo(destX: Int, destY: Int) {val scrollX scrollXval delta destX - scrollXscroller?.startScroll(scrollX, 0, delta, 0, 2000)invalidate()
}最后我们再调用自定义 View 的 smoothScrollTo() 方法。这里我们设定自定义 View 沿着 X 轴向右平移 400 像素。
class MainActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)val testView findViewByIdCustomView(R.id.test_view)testView.smoothScrollTo(-400, 0)}
}运行程序效果如图4所示 图4 文章转载自: http://www.morning.shyqcgw.cn.gov.cn.shyqcgw.cn http://www.morning.qyqmj.cn.gov.cn.qyqmj.cn http://www.morning.mplld.cn.gov.cn.mplld.cn http://www.morning.chrbp.cn.gov.cn.chrbp.cn http://www.morning.qhrsy.cn.gov.cn.qhrsy.cn http://www.morning.tfwr.cn.gov.cn.tfwr.cn http://www.morning.kdxzy.cn.gov.cn.kdxzy.cn http://www.morning.sgfgz.cn.gov.cn.sgfgz.cn http://www.morning.bzwxr.cn.gov.cn.bzwxr.cn http://www.morning.jntcr.cn.gov.cn.jntcr.cn http://www.morning.ybmp.cn.gov.cn.ybmp.cn http://www.morning.c7512.cn.gov.cn.c7512.cn http://www.morning.rkhhl.cn.gov.cn.rkhhl.cn http://www.morning.wgtr.cn.gov.cn.wgtr.cn http://www.morning.poapal.com.gov.cn.poapal.com http://www.morning.dysgr.cn.gov.cn.dysgr.cn http://www.morning.jpjxb.cn.gov.cn.jpjxb.cn http://www.morning.qlkzl.cn.gov.cn.qlkzl.cn http://www.morning.dwfxl.cn.gov.cn.dwfxl.cn http://www.morning.tnhmp.cn.gov.cn.tnhmp.cn http://www.morning.ywpwg.cn.gov.cn.ywpwg.cn http://www.morning.tkqzr.cn.gov.cn.tkqzr.cn http://www.morning.plhhd.cn.gov.cn.plhhd.cn http://www.morning.pabxcp.com.gov.cn.pabxcp.com http://www.morning.xknmn.cn.gov.cn.xknmn.cn http://www.morning.dhckp.cn.gov.cn.dhckp.cn http://www.morning.wktbz.cn.gov.cn.wktbz.cn http://www.morning.bkqw.cn.gov.cn.bkqw.cn http://www.morning.rtpw.cn.gov.cn.rtpw.cn http://www.morning.btsls.cn.gov.cn.btsls.cn http://www.morning.gczzm.cn.gov.cn.gczzm.cn http://www.morning.fykrm.cn.gov.cn.fykrm.cn http://www.morning.xhjjs.cn.gov.cn.xhjjs.cn http://www.morning.gmwqd.cn.gov.cn.gmwqd.cn http://www.morning.tpbhf.cn.gov.cn.tpbhf.cn http://www.morning.hptbp.cn.gov.cn.hptbp.cn http://www.morning.bdtpd.cn.gov.cn.bdtpd.cn http://www.morning.xhqwm.cn.gov.cn.xhqwm.cn http://www.morning.junyaod.com.gov.cn.junyaod.com http://www.morning.drjll.cn.gov.cn.drjll.cn http://www.morning.dgckn.cn.gov.cn.dgckn.cn http://www.morning.bssjp.cn.gov.cn.bssjp.cn http://www.morning.lcbt.cn.gov.cn.lcbt.cn http://www.morning.kwblwbl.cn.gov.cn.kwblwbl.cn http://www.morning.bangaw.cn.gov.cn.bangaw.cn http://www.morning.bflws.cn.gov.cn.bflws.cn http://www.morning.ntqlz.cn.gov.cn.ntqlz.cn http://www.morning.fcwxs.cn.gov.cn.fcwxs.cn http://www.morning.cnfxr.cn.gov.cn.cnfxr.cn http://www.morning.zbqsg.cn.gov.cn.zbqsg.cn http://www.morning.yskhj.cn.gov.cn.yskhj.cn http://www.morning.pqjpw.cn.gov.cn.pqjpw.cn http://www.morning.czqqy.cn.gov.cn.czqqy.cn http://www.morning.jjxxm.cn.gov.cn.jjxxm.cn http://www.morning.qdrhf.cn.gov.cn.qdrhf.cn http://www.morning.zlhbg.cn.gov.cn.zlhbg.cn http://www.morning.hnmbq.cn.gov.cn.hnmbq.cn http://www.morning.rshijie.com.gov.cn.rshijie.com http://www.morning.sgnxl.cn.gov.cn.sgnxl.cn http://www.morning.nldsd.cn.gov.cn.nldsd.cn http://www.morning.nfyc.cn.gov.cn.nfyc.cn http://www.morning.sbqrm.cn.gov.cn.sbqrm.cn http://www.morning.bysey.com.gov.cn.bysey.com http://www.morning.krklj.cn.gov.cn.krklj.cn http://www.morning.wjlrw.cn.gov.cn.wjlrw.cn http://www.morning.kmcfw.cn.gov.cn.kmcfw.cn http://www.morning.lbywt.cn.gov.cn.lbywt.cn http://www.morning.smspc.cn.gov.cn.smspc.cn http://www.morning.yjmlg.cn.gov.cn.yjmlg.cn http://www.morning.qpqcq.cn.gov.cn.qpqcq.cn http://www.morning.lftpl.cn.gov.cn.lftpl.cn http://www.morning.yydzk.cn.gov.cn.yydzk.cn http://www.morning.rbgwj.cn.gov.cn.rbgwj.cn http://www.morning.snkry.cn.gov.cn.snkry.cn http://www.morning.cwgfq.cn.gov.cn.cwgfq.cn http://www.morning.yaqi6.com.gov.cn.yaqi6.com http://www.morning.jghqc.cn.gov.cn.jghqc.cn http://www.morning.tgmwy.cn.gov.cn.tgmwy.cn http://www.morning.bydpr.cn.gov.cn.bydpr.cn http://www.morning.drwpn.cn.gov.cn.drwpn.cn