2016-09-28 36 views
1

我正在处理用户可以用手指触摸移动视图的项目。它的工作原理,但不准确的手指位置。我不是在问你有没有好的代码,而是想知道为什么我的代码使得视图不适合手指。它的观点一样,有更多的界限为约20dp.Here的代码:移动不适合手指的视图

activity_main.xml中

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout 
    xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:tools="http://schemas.android.com/tools" 
    android:id="@+id/lyRoot" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:paddingBottom="@dimen/activity_vertical_margin" 
    android:paddingLeft="@dimen/activity_horizontal_margin" 
    android:paddingRight="@dimen/activity_horizontal_margin" 
    android:paddingTop="@dimen/activity_vertical_margin" 
    tools:context="com.zihadrizkyef.dragviewwithfinger.MainActivity"> 

    <TextView 
     android:id="@+id/tvText" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_margin="0dp" 
     android:text="Hello World!"/> 
</LinearLayout> 

MainActivity.java

package com.zihadrizkyef.dragviewwithfinger; 

import android.support.v7.app.AppCompatActivity; 
import android.os.Bundle; 
import android.view.MotionEvent; 
import android.view.View; 
import android.view.ViewGroup; 
import android.widget.LinearLayout; 
import android.widget.TextView; 

public class MainActivity extends AppCompatActivity implements View.OnTouchListener { 
    ViewGroup lyRoot; 
    TextView tvText; 
    LinearLayout.LayoutParams layoutParams; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 

     lyRoot = (ViewGroup)findViewById(R.id.lyRoot); 
     tvText = (TextView)findViewById(R.id.tvText); 
     layoutParams = (LinearLayout.LayoutParams)tvText.getLayoutParams(); 

     lyRoot.setOnTouchListener(this); 
    } 

    @Override 
    public boolean onTouch(View v, MotionEvent event) { 
     int x = (int)event.getRawX(); 
     int y = (int)event.getRawY(); 
     if (event.getAction() == MotionEvent.ACTION_MOVE) { 
      layoutParams.leftMargin = x; 
      layoutParams.topMargin = y; 
      tvText.setLayoutParams(layoutParams); 
     } 
     lyRoot.invalidate(); 

     if (event.getAction() == MotionEvent.ACTION_UP) { 
      System.out.println("mouseX:"+x+" ; mouseY:"+y); 
      System.out.println("viewX:"+layoutParams.leftMargin+" ; viewY:"+layoutParams.topMargin); 
     } 

     return true; 
    } 
} 

回答

1

你应该使用拖动的距离,而不是屏幕上的坐标。

layoutParams.leftMargin = layoutParams.leftMargin + deltaX; 
layoutParams.topMargin = layoutParams.leftMargin + deltaY; 

你可以从Android开发者网站 https://developer.android.com/training/gestures/scale.html#drag
的完整的解决方案,您将不得不以使其适应您的需求。我改编了一下。

// The ‘active pointer’ is the one currently moving our object. 
private int mActivePointerId = INVALID_POINTER_ID; 

@Override 
public boolean onTouchEvent(MotionEvent ev) { 
    // Let the ScaleGestureDetector inspect all events. 
    mScaleDetector.onTouchEvent(ev); 

    final int action = MotionEventCompat.getActionMasked(ev); 

    switch (action) { 
     case MotionEvent.ACTION_DOWN: { 
      final int pointerIndex = MotionEventCompat.getActionIndex(ev); 
      final float x = MotionEventCompat.getX(ev, pointerIndex); 
      final float y = MotionEventCompat.getY(ev, pointerIndex); 

      // Remember where we started (for dragging) 
      mLastTouchX = x; 
      mLastTouchY = y; 
      // Save the ID of this pointer (for dragging) 
      mActivePointerId = MotionEventCompat.getPointerId(ev, 0); 
      break; 
     } 
     case MotionEvent.ACTION_MOVE: { 
      // Find the index of the active pointer and fetch its position 
      final int pointerIndex = 
        MotionEventCompat.findPointerIndex(ev, mActivePointerId); 

      final float x = MotionEventCompat.getX(ev, pointerIndex); 
      final float y = MotionEventCompat.getY(ev, pointerIndex); 

      // Calculate the distance moved 
      final float dx = x - mLastTouchX; 
      final float dy = y - mLastTouchY; 

      layoutParams.leftMargin += dx; 
      layoutParams.topMargin += dy; 
      tvText.setLayoutParams(layoutParams); 
      lyRoot.invalidate(); 

      // Remember this touch position for the next move event 
      mLastTouchX = x; 
      mLastTouchY = y; 
      break; 
     } 
     case MotionEvent.ACTION_UP: { 
      mActivePointerId = INVALID_POINTER_ID; 
      break; 
     } 
     case MotionEvent.ACTION_CANCEL: { 
      mActivePointerId = INVALID_POINTER_ID; 
      break; 
     } 
     case MotionEvent.ACTION_POINTER_UP: { 
      final int pointerIndex = MotionEventCompat.getActionIndex(ev); 
      final int pointerId = MotionEventCompat.getPointerId(ev, pointerIndex); 

      if (pointerId == mActivePointerId) { 
       // This was our active pointer going up. Choose a new 
       // active pointer and adjust accordingly. 
       final int newPointerIndex = pointerIndex == 0 ? 1 : 0; 
       mLastTouchX = MotionEventCompat.getX(ev, newPointerIndex); 
       mLastTouchY = MotionEventCompat.getY(ev, newPointerIndex); 
       mActivePointerId = MotionEventCompat.getPointerId(ev, newPointerIndex); 
      } 
      break; 
     } 
    } 
    return true; 
} 
+0

谢谢你的链接。但这并不意味着使用屏幕坐标是错误的,不是吗?我只是喜欢使用屏幕坐标。那么你能告诉我的代码错误吗? – zihadrizkyef

+1

不,我给你展示的例子也使用屏幕坐标,但它们随后会被调整。我的意思是你总是会有额外的余量(20dp或更多),因为'event.getRawX()'是你点击屏幕上的位置。你需要拖动的距离来设置精确* leftMargin * – vovahost

+0

尽量适应您的需求我发布的代码。它确实有效,因为我在我的一个项目中使用了它。否则,您将始终拥有该随机保证金。 – vovahost