Sliding of View in android

In fact, no matter what kind of sliding method, the basic idea is similar: when the click event is passed to the View, the system records the coordinates of the touch point, and when the finger moves, the system records the moved coordinates and calculates the offset , and modify the coordinates of the View through the offset.

Let's talk about the following sliding methods:

1. layout method

As you know, when drawing a View, the onlayout method is called to set the position to be displayed. Therefore, we can also control the coordinates of the view by modifying the left, top, right, and bottom attributes of the view. Next, let's define a View and implement sliding through the layout method:

package com.example.myapplication.views

import android.content.Context
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.View

class CustomView @JvmOverloads constructor(
    context: Context,
    attrs:AttributeSet? = null,
    defStyleAttr:Int= 0
) :View(
    context,attrs,defStyleAttr){
    private var lastX:Int = 0
    private var lastY:Int = 0

    override fun onTouchEvent(event: MotionEvent): Boolean {
        //获取手指触摸点的横坐标和纵坐标
        val x = event.x.toInt()
        val y = event.y.toInt()
        when(event.action) {
            MotionEvent.ACTION_DOWN -> {
                lastX = x
                lastY = y
            }
            MotionEvent.ACTION_MOVE -> {
                //计算移动距离
                val offsetX = x -lastX
                val offsetY = y -lastY
                //调用layout方法来重新放置他的位置
                layout(left+offsetX,top+offsetY,right + offsetX, bottom + offsetY)
            }
        }
        return true
    }
}

Then we put it in XML to use:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <com.example.myapplication.views.CustomView
        android:id="@+id/view_my"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:layout_gravity="center_horizontal"
        android:background="@mipmap/cai"/>

</LinearLayout>

Look at the effect:

 The effect of this movement is achieved.

2. Next, let's look at the offsetLeftAndRight() and offsetTopAndBottom() methods

These two methods are similar to the layout method, and we can modify them slightly. We replace the code block in ACTION_MOVE:

MotionEvent.ACTION_MOVE -> {
                //计算移动距离
                val offsetX = x -lastX
                val offsetY = y -lastY
                //对left和right进行偏移
                offsetLeftAndRight(offsetX)
                //对top和bottom进行偏移
                offsetTopAndBottom(offsetY)

//                //调用layout方法来重新放置他的位置
//                layout(left+offsetX,top+offsetY,right + offsetX, bottom + offsetY)
            }

can still be achieved.

3. The third method: LayoutParams (change layout parameters)

LayoutParams mainly saves the layout parameters of a View, so we can change the layout parameters of View through LayoutParams. So as to achieve the effect of changing the position of the View. We also replace the code block in ACTION_MOVE:

  MotionEvent.ACTION_MOVE -> {
                //计算移动距离
                val offsetX = x -lastX
                val offsetY = y -lastY
                val  layoutParams = layoutParams as LinearLayout.LayoutParams
                layoutParams.leftMargin = left + offsetX
                layoutParams.topMargin = top + offsetY
                setLayoutParams(layoutParams)

//                //对left和right进行偏移
//                offsetLeftAndRight(offsetX)
//                //对top和bottom进行偏移
//                offsetTopAndBottom(offsetY)

//                //调用layout方法来重新放置他的位置
//                layout(left+offsetX,top+offsetY,right + offsetX, bottom + offsetY)
            }
        }

However, after my experiment, this has a big deviation, always to the right. what reason?

4. Next, look at using the fourth method, using animation to slide.

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:fillAfter="true">
    <translate android:fromXDelta="0"
        android:toXDelta="300"
        />
</set>

Use the code to call:

findViewById<View>(R.id.view_my).animation = AnimationUtils.loadAnimation(this,R.anim.translate)

It should be noted that the view animation does not change the position parameters of the view. So when we click the Button, it will not be triggered, because its negative control must first judge whether the click event is within the range of the position parameters of the child view before it will be distributed to him. When we click the original position, it will respond. If we want him to respond to the moved position, that is to say, change the position parameters of the view, then property animation can be used.

  val customView = findViewById<View>(R.id.view_my)
        findViewById<Button>(R.id.btn_move).setOnClickListener {
            ObjectAnimator.ofFloat(customView,"translationX",0f,300f).setDuration(1000).start()
        }

5. Next, let's look at the fifth method, scrollTo and ScrollBy

scrollTo(x,y) means moving to a specific coordinate point, and scrollBy(dx,dy) means that the increment of movement is dx, dy. In fact, we know that scrollBy finally calculates the final coordinates by looking at the source code, and finally calls scrollTo . We can look at the source code:

 public void scrollBy(int x, int y) {
        scrollTo(mScrollX + x, mScrollY + y);
    }

It should be noted that scrollTo and ScrollBy are mobile content. If we set Bacgroud, we will find no effect. Can be changed to:

 <com.example.myapplication.views.CustomView
        android:id="@+id/view_my"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:layout_gravity="center_horizontal"
        android:foreground="@mipmap/cai"/>
  findViewById<Button>(R.id.btn_move).setOnClickListener {
            customView.scrollBy(50,100)
//            ObjectAnimator.ofFloat(customView,"translationX",0f,300f).setDuration(1000).start()
        }

Use the foreground. Then look at the effect:

 It started like this, and then we clicked the button, and it became like this:

 Have you discovered something miraculous? Click again:

 Good guy, almost out of sight. What is the reason? There are two strange phenomena here, the first is that he seems to move in the opposite direction, and the second is that it is getting smaller and smaller. To be precise, it seems that it is not zoomed out, but only part of it can be seen.

This is due to the difference in reference objects. Suppose, we compare the mobile phone screen to a magnifying glass. The following content is treated as a newspaper. When we call this method, we actually make the magnifying glass move down relative to the view, and the place that the magnifying glass cannot see does not exist. That's why he looks like he's moved up and to the left. Then, because we are moving the content, the View itself does not move, so its foreground color cannot be seen.

If we want to be able to move with our fingers, we can modify it like this in the move method:

MotionEvent.ACTION_MOVE -> {
                //计算移动距离
                val offsetX = x -lastX
                val offsetY = y -lastY

                val parentView = parent as View
                parentView.scrollBy(-offsetX,-offsetY)
}

Here, the opposite value is taken, as Gang just said, because the reference object will lead to the opposite vision. And to get his parent, because this view belongs to the content of his parent. Therefore, he can perform related actions.

6. Let's look at the sixth method Scroller

When we use the scrollTo/scrollBy method to slide, the process is completed instantly. So the experience is not very good. We can use scroller to achieve sliding with transition effect. However, the scroller itself cannot realize the sliding of the View. It needs to cooperate with the computeScroller method of the View to achieve the elastic sliding effect. Let's see the code implementation:

First, define a member variable:

 private val mScroller = Scroller(context)

Next, we rewrite the computeScroll method, which is called in the draw method when the system draws the View.

Let's first define a method in CustomView:

 fun smoothScrollTo(destX:Int, destY:Int){
        val scrollX = scrollX
        val delta  = destX - scrollX
        mScroller.startScroll(scrollX,0,delta,2,2000)
        invalidate()
    }

This method is provided for external calls, and the parameters are X and Y that you want to offset.

scrollX is the value that has already been slid so far, and the value that has already been slid is subtracted from the one to be offset by the target, which is what is left. Call the scroller.startScroll() method. Set a duration. We call invalidate() and start redrawing. At this time, the computeScroller method of the view will be called. Here we call the scrollTo method of the viewGroup of the parent space to obtain the current small slide value, and then perform a small slide. Then call the invalidate() method to continuously redraw.

 override fun computeScroll() {
        super.computeScroll()
        if (mScroller.computeScrollOffset()) {
            (parent as View).scrollTo(mScroller.currX,mScroller.currY)
            invalidate()
        }
    }

Finally, we call in the activity:
 

 customView.smoothScrollTo(-400,0)

Pan 400 to the right.

Guess you like

Origin blog.csdn.net/howlaa/article/details/128452434