文章转载只能用于非商业性质,且不能带有虚拟货币、积分、注册等附加条件。转载须注明出处http://blog.csdn.net/flowingflying/以及作者@恺风Wei。
拖拽(Drag and Drop)在Windows电脑很常用,用户使用很方便。在Android中,我们见图标拖入到垃圾桶进行应用删除,以及重新安排图标,这些都是拖拽的例子。
Android3.0引入了拖拽能力,而在此之前,开发者可以利用触屏MotionEvent来实现。市面当仍有少量的Android2.x机器,我们先来看看自行通过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开发相关文章