一个跟随手指滑动的图片 -- 单点触摸

深藏阁楼爱情的钟 2023-10-15 16:56 90阅读 0赞

本篇为系列文章
一个跟随手指滑动的图片 – 单点触摸
自定义 View:多点触控 (一)— 手指接力
自定义View:多点触控(二)— 多指协作
自定义 View:多点触控 (三)— 各自为战

首先,先创建一个view

  1. import android.content.Context
  2. import android.util.AttributeSet
  3. import android.view.View
  4. class DragView(context: Context, attrs: AttributeSet?) : View(context, attrs) {
  5. }

实现一个自定义的图片绘制,直接重写 onDraw() 方法,使用 drawBitmap 来绘制一个图片

  1. import android.content.Context
  2. import android.graphics.BitmapFactory
  3. import android.graphics.Canvas
  4. import android.graphics.Paint
  5. import android.util.AttributeSet
  6. import android.view.View
  7. import com.example.viewtest.R
  8. class DragView(context: Context, attrs: AttributeSet?) : View(context, attrs) {
  9. private val bitmap = BitmapFactory.decodeResource(resources, R.drawable.ic_launcher_foreground)
  10. private val paint = Paint(Paint.ANTI_ALIAS_FLAG)
  11. override fun onDraw(canvas: Canvas?) {
  12. super.onDraw(canvas)
  13. canvas?.drawBitmap(bitmap, 0f, 0f, paint)
  14. }
  15. }

xml中使用我们定义的 view

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <com.example.viewtest.view.DragView xmlns:android="http://schemas.android.com/apk/res/android"
  3. xmlns:app="http://schemas.android.com/apk/res-auto"
  4. xmlns:tools="http://schemas.android.com/tools"
  5. android:layout_width="match_parent"
  6. android:layout_height="match_parent"
  7. tools:context=".MainActivity" />

这个时候就完成了一个图片出现在左上角的操作

然后我们需要在移动事件中去时时更新我们的图片位置,就可以实现一个图片随手指拖动的效果了

  1. import android.content.Context
  2. import android.graphics.BitmapFactory
  3. import android.graphics.Canvas
  4. import android.graphics.Paint
  5. import android.util.AttributeSet
  6. import android.view.MotionEvent
  7. import android.view.View
  8. import com.example.viewtest.R
  9. class DragView(context: Context, attrs: AttributeSet?) : View(context, attrs) {
  10. private val bitmap = BitmapFactory.decodeResource(resources, R.drawable.ic_launcher_foreground)
  11. private val paint = Paint(Paint.ANTI_ALIAS_FLAG)
  12. private var offsetX = 0f
  13. private var offsetY = 0f
  14. override fun onDraw(canvas: Canvas?) {
  15. super.onDraw(canvas)
  16. // 绘制时候使用更新后的坐标
  17. canvas?.drawBitmap(bitmap, offsetX, offsetY, paint)
  18. }
  19. override fun onTouchEvent(event: MotionEvent?): Boolean {
  20. when(event?.action) {
  21. MotionEvent.ACTION_MOVE -> {
  22. // 记录最新的手指位置
  23. offsetX = event.x
  24. offsetY = event.y
  25. // 触发重绘
  26. invalidate()
  27. }
  28. }
  29. return true
  30. }
  31. }

在上面代码中,我们在移动事件中,将移动的坐标实时保存在变量当中,然后触发重绘,在绘制方法中,也配合使用更改后的坐标变量

这样我们就实现了一个随手指移动的view效果

但是实际运行中会发现,拖动刚开始会闪一下,而且总是图片的左上角在我们手指的位置跟随手指移动,而不是我们按下的位置跟随手指移动。

这是因为我们的手指坐标传递给的是图片的左上角,如果要实现按下的位置跟随手指移动,

图片的左上角应该向左移动我们按下的距离和到左边的距离差,并且向上移动我们按下的距离和到上面的距离差

所以说我们要记录下按下的坐标,在移动的时候减掉

  1. import android.content.Context
  2. import android.graphics.BitmapFactory
  3. import android.graphics.Canvas
  4. import android.graphics.Paint
  5. import android.util.AttributeSet
  6. import android.view.MotionEvent
  7. import android.view.View
  8. import com.example.viewtest.R
  9. class DragView(context: Context, attrs: AttributeSet?) : View(context, attrs) {
  10. private val bitmap = BitmapFactory.decodeResource(resources, R.drawable.ic_launcher_foreground)
  11. private val paint = Paint(Paint.ANTI_ALIAS_FLAG)
  12. private var offsetX = 0f
  13. private var offsetY = 0f
  14. private var downX = 0f
  15. private var downY = 0f
  16. override fun onDraw(canvas: Canvas?) {
  17. super.onDraw(canvas)
  18. // 绘制时候使用更新后的坐标
  19. canvas?.drawBitmap(bitmap, offsetX, offsetY, paint)
  20. }
  21. override fun onTouchEvent(event: MotionEvent?): Boolean {
  22. when(event?.action) {
  23. MotionEvent.ACTION_DOWN -> {
  24. // 记录手指按下的坐标
  25. downX = event.x
  26. downY = event.y
  27. }
  28. MotionEvent.ACTION_MOVE -> {
  29. // 记录最新的手指位置
  30. offsetX = event.x - downX
  31. offsetY = event.y - downY
  32. // 触发重绘
  33. invalidate()
  34. }
  35. }
  36. return true
  37. }
  38. }

运行以上代码,会发现在第二次进行拖动操作的时候,图片会跳到左上角,开始跟随手指移动,并不是从上一次拖动的结束位置继续的,所以说我们还要计算下结束时的位置,在移动的时候加上上次的位置,可以在抬起时计算结束时的位置,也可以在下次按下时计算,这里选择在按下时计算,方便后续讲多指操作时候的理解

  1. import android.content.Context
  2. import android.graphics.BitmapFactory
  3. import android.graphics.Canvas
  4. import android.graphics.Paint
  5. import android.util.AttributeSet
  6. import android.view.MotionEvent
  7. import android.view.View
  8. import com.example.viewtest.R
  9. class DragView(context: Context, attrs: AttributeSet?) : View(context, attrs) {
  10. private val bitmap = BitmapFactory.decodeResource(resources, R.drawable.ic_choice_select)
  11. private val paint = Paint(Paint.ANTI_ALIAS_FLAG)
  12. private var offsetX = 0f
  13. private var offsetY = 0f
  14. private var downX = 0f
  15. private var downY = 0f
  16. private var originOffsetX = 0f
  17. private var originOffsetY = 0f
  18. override fun onDraw(canvas: Canvas?) {
  19. super.onDraw(canvas)
  20. // 绘制时候使用更新后的坐标
  21. canvas?.drawBitmap(bitmap, offsetX, offsetY, paint)
  22. }
  23. override fun onTouchEvent(event: MotionEvent?): Boolean {
  24. when (event?.action) {
  25. MotionEvent.ACTION_DOWN -> {
  26. // 记录手指按下的坐标
  27. downX = event.x
  28. downY = event.y
  29. originOffsetX = offsetX
  30. originOffsetY = offsetY
  31. }
  32. MotionEvent.ACTION_MOVE -> {
  33. // 记录最新的手指位置
  34. offsetX = event.x - downX + originOffsetX
  35. offsetY = event.y - downY + originOffsetY
  36. // 触发重绘
  37. invalidate()
  38. }
  39. }
  40. return true
  41. }
  42. }

好了,以上上最重代码,实现了一个随手指移动的 View 的效果

发表评论

表情:
评论列表 (有 0 条评论,90人围观)

还没有评论,来说两句吧...

相关阅读