文章转载只能用于非商业性质,且不能带有虚拟货币、积分、注册等附加条件。转载须注明出处http://blog.csdn.net/flowingflying/以及作者@恺风Wei。
我们在上面的fragment中放入LinearLayout,里面放入我们自定的圆点MyNewDot,相关的layout文件如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout …… android:orientation="vertical" >
<cn.wei.flowingflying.testdraganddrop.MyNewDot android:id="@+id/dot1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="30dp"
android:tag="Blue Dot"
dot:color="#ff3333ff"
dot:radius="20dp" />
<cn.wei.flowingflying.testdraganddrop.MyNewDot android:id="@+id/dot2"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="10dp"
android:tag="Red Dot"
dot:color="#ffff3333"
dot:radius="30dp" />
</LinearLayout>
我们注意到在xml文件中有两个自定义的属相dot:color和dot:radius分别定义圆点的颜色和大小。我们在res/values中增加一个attribute.xml文件来对这些自行一属性Dot(不区分大小写)进行描述,定义属性前缀和属性名称,以及属性值的类型,如下。
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="Dot">
<attr name="color" format="color"/>
<attr name="radius" format="dimension"/>
</declare-styleable>
</resources>
Paletter类代码如下,很简单:
public class Palette extends Fragment{
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.palette, container, false);
return v;
}
}
我们重点看看如何实现自定义的MyNewDot,我们需要在代码对自定义的属性进行读取,如下:
public class MyNewDot extends View implements OnDragListener{
private String tag = "MyNewDot";
private static final int DEFAULT_RADIUS = 20;
private static final int DEFAULT_COLOR = Color.BLACK;
private static final int SELECTED_COLOR = Color.MAGENTA;
private int mRadius = DEFAULT_RADIUS;
private int mColor = DEFAULT_COLOR;
private boolean inDrag = false;
public MyNewDot(Context context ,AttributeSet attrs){
super(context,attrs);
tag = (String)getTag();
//【1】读取自定义的属性:根据R.styleable.Dot来解释属性
TypedArray myAttrs = context.obtainStyledAttributes(attrs, R.styleable.Dot);
int numAttrs = myAttrs.getIndexCount();
for(int i = 0 ; i < numAttrs; i ++){
int attr = myAttrs.getIndex(i);
switch(attr){
case R.styleable.Dot_color:
mColor = myAttrs.getColor(attr, DEFAULT_COLOR);
break;
case R.styleable.Dot_radius:
//注意这里的单位是pixel,和xml中的单位不同
mRadius = myAttrs.getDimensionPixelSize(attr, DEFAULT_RADIUS);
break;
}
}
myAttrs.recycle();
Log.v(tag,"radius:" + mRadius + "px color:" + mColor);
// 构造一个Paint
myNormalPaint = new Paint();
myNormalPaint.setColor(mColor);
myNormalPaint.setAntiAlias(true);
//构造另一个Paint,当检查到被拖拽时,颜色发生变化
myDraggingPaint = new Paint();
myDraggingPaint.setColor(SELECTED_COLOR);
myDraggingPaint.setAntiAlias(true);
}
@Override //【2】根据xml的参数大小,重新设置圆点的size,如果不重新进行设定,则尽可能占空间,小例子有上下两个圆点,第一个控件将占满parent的空间,第二个控件的高度为0,要计算真实需要的空间
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int size = 2 * mRadius + getPaddingLeft() + getPaddingRight();
setMeasuredDimension(size, size);
}
@Override //【3】画圆点
public void draw(Canvas canvas) {
//计算圆心
float cx = this.getWidth()/2 + getLeftPaddingOffset();
float cy = this.getHeight()/2 + getTopPaddingOffset();
//设置paint
Paint paint = inDrag ? myDraggingPaint : myNormalPaint;
canvas.drawCircle(cx, cy, mRadius, paint);
invalidate(); //重画
}
}
当检测到用户长按圆点时,表示要启动拖拽,相关代码如下:
public MyNewDot(Context context ,AttributeSet attrs){
......
//当检测到常按是,启动拖拽
setOnLongClickListener(new OnLongClickListener() {
private boolean mDragInProgress;
@Override
public boolean onLongClick(View v) {
// 在ClipData中携带信息,小例子只简单地携带tag信息,可以用来标识view
ClipData data = ClipData.newPlainText("DragData", (String)v.getTag());
//startDrag()启动拖拽,方法中第一个参数是ClipData;第二个参数是通过DragShadowBuilder()创建拖拽的暗影,当然也可以设置为其他的形状的view;第三个参数是local-state对象,可放入DragEvent用来传递信息,通过event.getLocalState()获取,本例,我们就将被拖拽view作为对象进行传递;第四个参数flag,设置为0。
mDragInProgress = v.startDrag(data, new View.DragShadowBuilder(v), (Object) v, 0);
Log.v((String)v.getTag(), "Starting drag ? " + mDragInProgress);
return true;
}
});
}
实际上被拖拽的圆点本身一般并不需要进行监听拖拽,我们只是进一步地学习onDrag()的监听触发机制。为此,我们在检测到started的时候,改变圆点的颜色,并在结束时ended,恢复圆点的颜色。相关代码如下:
public class MyNewDot extends View implements OnDragListener{
public MyNewDot(Context context ,AttributeSet attrs){
......
setOnDragListener(this); //设置监听器
}
... ...
@Override /* 我们在检测到started的时候,改变圆点颜色,并在结束时ended,恢复圆点的颜色*/
public boolean onDrag(View v, DragEvent event) {
String dotTag = (String)v.getTag();
// 判断是否拖拽本view,在小例子中,有两个MyNewDot进行拖拽,需要进行判断是否是我们所关心的对象,本例子,已经在localState中设置为被拖拽对象,可用来进行比较,如果不是自己,直接返回false。 注意onDrag()中第一个参数是接收拖拽事件的对象,而非被拖拽的对象,本例就是this自己
if(event.getLocalState() !=this){
Log.v(dotTag,"This Drag event is not for use");
return false;
}
boolean result = true;
float x = event.getX();
float y = event.getY();
//当检测到start时,改变颜色,当检测到end时,恢复颜色,其他的action给出log,帮助学习onDrag()
switch(event.getAction()){
case DragEvent.ACTION_DRAG_STARTED:
Log.v(dotTag,"Drag started. x=" + x + " y=" + y);
inDrag = true;
break;
case DragEvent.ACTION_DRAG_LOCATION: //在圆点区域内,位置移动会触发
Log.v(dotTag,"Drag processing... x=" + x + " y=" + y);
break;
case DragEvent.ACTION_DRAG_ENTERED: //在started后,我们马上看到entered,因为圆点一开始就在自己的位置上,所以一开始就entered
Log.v(dotTag,"Drag entered at x=" + x + " y=" + y);
break;
case DragEvent.ACTION_DRAG_EXITED: //圆点拖拽的暗影离开圆点区域
Log.v(dotTag,"Drag exited at x=" + x + " y=" + y);
break;
case DragEvent.ACTION_DROP: //对于圆点在自己的区域内drop,圆点不关心,因为它是被拖拽的对象,不是目标位置对象,无需任何处理,可以返回false,不过下个动作就是ended,返回true也无所谓。
Log.v(dotTag,"Drag droped at x=" + x + " y=" + y);
break;
case DragEvent.ACTION_DRAG_ENDED:
Log.v(dotTag,"Drag ended. x=" + x + " y=" + y);
inDrag = false;
break;
default:
Log.v(dotTag,"Drag other action : " + action + " x=" + x + " y=" + y);
result = false;
break;
}
return result;
}
}
相关小例子代码:Pro Android学习:拖拽小例子
相关链接:我的Android开发相关文章