我想做一个简单的控件:一个里面有视图的容器。如果我触摸容器并移动手指,我想让视图跟着我的手指移动。
我应该使用什么样的容器(布局)?如何做到这一点?
我不需要使用一个表面,但一个简单的布局。
我想做一个简单的控件:一个里面有视图的容器。如果我触摸容器并移动手指,我想让视图跟着我的手指移动。
我应该使用什么样的容器(布局)?如何做到这一点?
我不需要使用一个表面,但一个简单的布局。
当前回答
按照@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;
}
其他回答
按照@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;
}
我推荐使用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是视图的父视图。
改变了一点由@Vyacheslav Shylkin提供的解决方案,以删除手动输入数字的依赖性。
import android.app.Activity;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.ImageView;
import android.widget.RelativeLayout;
public class MainActivity extends Activity implements View.OnTouchListener
{
private int _xDelta;
private int _yDelta;
private int _rightMargin;
private int _bottomMargin;
private ImageView _floatingView;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
this._floatingView = (ImageView) findViewById(R.id.textView);
this._floatingView.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener()
{
@Override
public boolean onPreDraw()
{
if (_floatingView.getViewTreeObserver().isAlive())
_floatingView.getViewTreeObserver().removeOnPreDrawListener(this);
updateLayoutParams(_floatingView);
return false;
}
});
this._floatingView.setOnTouchListener(this);
}
private void updateLayoutParams(View view)
{
this._rightMargin = -view.getMeasuredWidth();
this._bottomMargin = -view.getMeasuredHeight();
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(view.getMeasuredWidth(), view.getMeasuredHeight());
layoutParams.bottomMargin = this._bottomMargin;
layoutParams.rightMargin = this._rightMargin;
view.setLayoutParams(layoutParams);
}
@Override
public boolean onTouch(View view, MotionEvent event)
{
if (view == this._floatingView)
{
final int X = (int) event.getRawX();
final int Y = (int) event.getRawY();
switch (event.getAction() & MotionEvent.ACTION_MASK)
{
case MotionEvent.ACTION_DOWN:
RelativeLayout.LayoutParams lParams = (RelativeLayout.LayoutParams) view.getLayoutParams();
this._xDelta = X - lParams.leftMargin;
this._yDelta = Y - lParams.topMargin;
break;
case MotionEvent.ACTION_MOVE:
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) view.getLayoutParams();
layoutParams.leftMargin = X - this._xDelta;
layoutParams.topMargin = Y - this._yDelta;
layoutParams.rightMargin = this._rightMargin;
layoutParams.bottomMargin = this._bottomMargin;
view.setLayoutParams(layoutParams);
break;
}
return true;
}
else
{
return false;
}
}
}
在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
})