Pro Android学习笔记(一四七):拖拽(1):通过MotionEvent来实现

文章转载只能用于非商业性质,且不能带有虚拟货币、积分、注册等附加条件。转载须注明出处http://blog.csdn.net/flowingflying/以及作者@恺风Wei。

拖拽(Drag and Drop)在Windows电脑很常用,用户使用很方便。在Android中,我们见图标拖入到垃圾桶进行应用删除,以及重新安排图标,这些都是拖拽的例子。

Android3.0引入了拖拽能力,而在此之前,开发者可以利用触屏MotionEvent来实现。市面当仍有少量的Android2.x机器,我们先来看看自行通过MotionEvent的实现方式。

小例子

小例子允许拖拽一个蓝点,如果拖拽到特定的计数器位置,计数器加1,蓝点复位。

Pro Android学习笔记(一四七):拖拽(1):通过MotionEvent来实现_第1张图片

layout的xml代码如下:

<?xml version="1.0" encoding="utf-8"?>
<!-- 使用了FrameLayout,因此自定义的Dot可以层叠在LineareLayout上面 -->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" …… >
    <LinearLayout android:id="@+id/counters"  android:orientation="vertical" …….>
        <TextView android:id="@+id/counter_top"
            android:text="0"
            android:background="#aaaaaa"
            android:layout_width="60dp"
            android:layout_height="wrap_content"
            android:layout_gravity="right"
            android:layout_marginTop="30dp"
            android:layout_marginBottom="30dp"
            android:padding="10dp"/>         
        <TextView android:id="@+id/counter_middle" …… >       <!-- 同上,略  -->
        <TextView android:id="@+id/counter_buttom" …… >       <!-- 同上,略  -->
    </LinearLayout>
    <!-- 自定义的View MyDot-->
    <cn.wei.flowingflying.testdraganddrop.MyDot android:id="@+id/dot"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
</FrameLayout>

相关的Activity很简单,如下:

public class TestOldDrapAndDropActivity extends Activity{
    public LinearLayout countersLayout = null;
    @Override
    protected void onCreate(Bundle savedInstanceState) { 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.drag_drop_old_activity);
        countersLayout = (LinearLayout)findViewById(R.id.counters);
    }
}

关键在于自定义的View,即MyDot,代码如下:

public class MyDot extends View{
    private Context myContext;
    private Paint myPaint;     
    private float left = 0f;
    private float top = 0f;
    private float radius = 20f;
    private float offsetX, offsetY; 
     
    public MyDot(Context context, AttributeSet attriSet){
        super(context,attriSet);
        myContext = context;         
        myPaint = new Paint();
        myPaint.setColor(Color.BLUE);
        myPaint.setAntiAlias(true);       
    } 

   @Override //【1】画出view,(left,top)为该Dot的左上角,圆心在(left+radius,top+radius)。
    public void draw(Canvas canvas) {
        canvas.drawCircle(left + radius, top + radius, radius, myPaint);
    } 

    @Override //【2】通过MotionEvent,自行处理拖拽。
    public boolean onTouchEvent(MotionEvent event) {                 
        float eventX = event.getX();
        float eventY = event.getY();
       
        switch(event.getAction()){
        case MotionEvent.ACTION_DOWN:
            //【2.1】确保按在Dot上,如果距离太远,认为用户并非真的要拖拽Dot,这时返回false,不再处理该动作。(left+radius,top+radius)为圆心,要确保在 圆心±radius范围内。由于手指比较粗大,我们将范围再扩大一点,为圆心±(radius+20)范围中

            if(!(left-20 < eventX && eventX < left + radius*2 + 20
                    && top -20 < eventY && eventY < top + radius*2 + 20)){
                return false; //该动作不再处理
            }
           //【2.2】由于用户不会正好地按在Dot的左上角(draw()根据此点构图),记住触点与左上角的偏差
            offsetX = eventX - left;
            offsetY = eventY - top;
            break;
           
        //【2.3】跟随移动   
        case MotionEvent.ACTION_MOVE:       
        case MotionEvent.ACTION_CANCEL:
            left = eventX - offsetX;
            top = eventY - offsetY;           
            break;
       
        //【2.4】结束拖拽,进行相应处理:如果拖拽到特定的区域,进行相关的处理,本例子如在counter内,则counter加一,且Dot复位。在某些情况,我们在处理后会设置view不可视,或更直接地将view从viewGroup中删除removeView()
        case MotionEvent.ACTION_UP:

            checkDrop(left + radius,top+radius);
            break;
        }
       
        //-----------下面确保Dot不会移出屏幕范围-------------,从略 
        … …

        
        invalidate(); //【2.5】redraw if can seen
        return true;
    } 
    
   //【2.4】计算是否与Textview的范围重叠,如重叠,进行counter++,并将Dot复位到左上角
    private void checkDrop(float x, float y){  
        Log.v("MyDot", "Check target : " + x + "," + y);
        int viewCount = ((TestOldDrapAndDropActivity)myContext).countersLayout.getChildCount();  
        for(int i = 0 ; i < viewCount; i ++){
            View view = ((TestOldDrapAndDropActivity)myContext).countersLayout.getChildAt(i);
            if(view.getClass() == TextView.class){
                // Dot在TextView(左上角)的右边,才是目标X坐标位置 
                if( !(x > view.getLeft() )){
                    continue;
                }
               
                // Dot的y值TextView上下之间,目标Y坐标范围 
                if( !(view.getTop() < y && y < view.getBottom())){
                    continue;
                }
               
                //Dot落在TextView的范围中
                Log.v("MyDot", "--检测到在TextView中");
                int count = Integer.parseInt(((TextView)view).getText().toString());
                ((TextView)view).setText(String.valueOf(++count));                 
                //Dot复位
                left = 0;
                top = 0;
                return;
            }
        }
    }
   
}

 相关小例子代码:Pro Android学习:拖拽小例子

相关链接:我的Android开发相关文章

你可能感兴趣的:(Pro Android学习笔记(一四七):拖拽(1):通过MotionEvent来实现)