我想做一个简单的控件:一个里面有视图的容器。如果我触摸容器并移动手指,我想让视图跟着我的手指移动。

我应该使用什么样的容器(布局)?如何做到这一点?

我不需要使用一个表面,但一个简单的布局。


当前回答

在Kotlin中实现相同

    rightPanel.setOnTouchListener(View.OnTouchListener { view, event ->
        when (event?.action) {
            MotionEvent.ACTION_DOWN -> {

                rightDX = view!!.x - event.rawX
                // rightDY = view!!.getY() - event.rawY;

            }
            MotionEvent.ACTION_MOVE -> {

                var displacement = event.rawX + rightDX

                view!!.animate()
                        .x(displacement)
                        // .y(event.getRawY() + rightDY)
                        .setDuration(0)
                        .start()
            }
            else -> { // Note the block
                return@OnTouchListener false
            }
        }
        true
 })

其他回答

和@Alex Karshin的答案一样,我做了一点改变。

public class MovingObject implements OnTouchListener {
private RelativeLayout.LayoutParams lParams;
private PointF viewPoint, prePoint, currPoint;

public MovingObject() {
    lParams = null;
    viewPoint = new PointF();
    prePoint = new PointF();
    currPoint = new PointF();
}

public boolean onTouch(View view, MotionEvent event) {
    switch (event.getAction() & MotionEvent.ACTION_MASK) {
    case MotionEvent.ACTION_DOWN:
        viewPoint.set(view.getX(), view.getY());
        prePoint.set(event.getRawX(), event.getRawY());
        lParams = (RelativeLayout.LayoutParams) view.getLayoutParams();
        break;
    case MotionEvent.ACTION_UP:
        break;
    case MotionEvent.ACTION_POINTER_DOWN:
        break;
    case MotionEvent.ACTION_POINTER_UP:
        break;
    case MotionEvent.ACTION_MOVE:
        currPoint.set(event.getRawX(), event.getRawY());
        moveToCurrentPoint(view);
        break;
    }
    view.invalidate();
    return true;
}

private void moveToCurrentPoint(View view) {
    float dx = currPoint.x - prePoint.x - prePoint.x + viewPoint.x;
    float dy = currPoint.y - prePoint.y - prePoint.y + viewPoint.y;
    lParams.leftMargin = (int) (prePoint.x + dx);
    lParams.topMargin = (int) (prePoint.y + dy);
    view.setLayoutParams(lParams);
}
}

按照@Andrew方法,如果你想要移动视图的中心,你只需要减去视图的一半高度和一半宽度。

float dX, dY;

@Override
public boolean onTouchEvent(View view, MotionEvent event) {
    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            dX = view.getX() - event.getRawX();
            dY = view.getY() - event.getRawY();
            break;
        case MotionEvent.ACTION_MOVE:
            view.animate()
                .x(event.getRawX() + dX - (view.getWidth() / 2f))
                .y(event.getRawY() + dY - (view.getHeight() / 2f))
                .setDuration(0)
                .start();
            break;
        default:
            return false;
    }
    return true;
}     

在Kotlin中实现相同

    rightPanel.setOnTouchListener(View.OnTouchListener { view, event ->
        when (event?.action) {
            MotionEvent.ACTION_DOWN -> {

                rightDX = view!!.x - event.rawX
                // rightDY = view!!.getY() - event.rawY;

            }
            MotionEvent.ACTION_MOVE -> {

                var displacement = event.rawX + rightDX

                view!!.animate()
                        .x(displacement)
                        // .y(event.getRawY() + rightDY)
                        .setDuration(0)
                        .start()
            }
            else -> { // Note the block
                return@OnTouchListener false
            }
        }
        true
 })

我推荐使用view。translationX和view。翻译来移动你的观点。

Kotlin snippet:

yourView.translationX = xTouchCoordinate
yourView.translationY = yTouchCoordinate

创建一个自定义的触摸监听器类(在Kotlin中):

(这段代码限制了视图从父视图中拖出)

class CustomTouchListener(
  val screenWidth: Int, 
  val screenHeight: Int
) : View.OnTouchListener {
    private var dX: Float = 0f
    private var dY: Float = 0f

    override fun onTouch(view: View, event: MotionEvent): Boolean {

        val newX: Float
        val newY: Float

        when (event.action) {
            MotionEvent.ACTION_DOWN -> {
                dX = view.x - event.rawX
                dY = view.y - event.rawY
            }
            MotionEvent.ACTION_MOVE -> {

                newX = event.rawX + dX
                newY = event.rawY + dY

                if ((newX <= 0 || newX >= screenWidth - view.width) || (newY <= 0 || newY >= screenHeight - view.height)) {
                    return true
                }

                view.animate()
                    .x(newX)
                    .y(newY)
                    .setDuration(0)
                    .start()
            }
        }
        return true
    }
}

如何使用它?

parentView.viewTreeObserver.addOnGlobalLayoutListener { view.setOnTouchListener(CustomTouchListener(parentView.width, parentView.height)) }

parentView是视图的父视图。