Android Api Demos登顶之路(106)View-->DragAndDrop
2015-10-21 20:28
375 查看
这个demo演示了拖放功能的实现
同样使用了自定义属性和自定义视图
自定义属性:attr.xml
DraggableDot.java
activity_main.xml
MainActivity
同样使用了自定义属性和自定义视图
自定义属性:attr.xml
<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="DraggableDot"> <attr name="radius" format="dimension"/> <attr name="legend" format="string"/> <attr name="anr"> <enum name="none" value="0"/> <enum name="thumbnail" value="1"/> <enum name="drop" value="2"/> </attr> </declare-styleable> </resources>
DraggableDot.java
/*定制一个自定义的视图组件*/ public class DraggableDot extends View { private static final String TAG = "DraggableDot"; // 是否处于拖动的状态 private boolean mDragInProgress; // 拖拽阴影是否进入当前View(即当前View是否接收到了拖动进入的事件) private boolean mHovering; // view是否接受拖放事件 private boolean mAcceptsDrag; // 用于显示拖动的数据 private TextView mReportTextView; private Paint mPaint; private Paint mLegendPaint; private Paint mGlow; private static final int NUM_GLOW_STEPS = 10; private static final int GREEN_STEP = 0x0000FF00 / NUM_GLOW_STEPS; private static final int WHITE_STEP = 0x00FFFFFF / NUM_GLOW_STEPS; private static final int ALPHA_STEP = 0xFF000000 / NUM_GLOW_STEPS; private int mRadius; private int mAnrType; private CharSequence mLegend; private static final int ANR_SHADOW = 1; private static final int ANR_DROP = 2; private void sleepSixSecond() { // 获取自系统启动至当前的时间,不包括系统休眠的时间 long start = SystemClock.uptimeMillis(); do { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } while (SystemClock.uptimeMillis() < start + 6000); } // 绘制拖拽阴影的类 private class ANRShadowBuilder extends DragShadowBuilder { boolean mDoAnr; public ANRShadowBuilder(View view, boolean doAnr) { super(view); mDoAnr = doAnr; } // 绘制阴影 @Override public void onDrawShadow(Canvas canvas) { if (mDoAnr) { sleepSixSecond(); } super.onDrawShadow(canvas); } } public DraggableDot(Context context, AttributeSet attrs) { //必须调用这个构造方法,不能调用super(context); super(context,attrs); setFocusable(true); setClickable(true); mLegend = ""; mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); mPaint.setStrokeWidth(6); mPaint.setColor(0xffd00000); mLegendPaint = new Paint(); mLegendPaint.setAntiAlias(true); mLegendPaint.setTextAlign(Paint.Align.CENTER); mLegendPaint.setColor(0xfff0f0ff); mGlow = new Paint(); mGlow.setAntiAlias(true); mGlow.setStrokeWidth(1); mGlow.setStyle(Paint.Style.STROKE); TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DraggableDot); int N = a.getIndexCount(); for (int i = 0; i < N; i++) { // 遍历所有自定义的属性 int attr = a.getIndex(i); switch (attr) { case R.styleable.DraggableDot_radius: // 获取某个dimension的值,无论单位是dp、sp或px都会乘以density mRadius = a.getDimensionPixelSize(attr, 0); break; case R.styleable.DraggableDot_legend: mLegend = a.getText(attr); break; case R.styleable.DraggableDot_anr: mAnrType = a.getInt(attr, 0); break; } } a.recycle(); setOnLongClickListener(new OnLongClickListener() { @Override public boolean onLongClick(View v) { // 定义拖动数据,为普通的文本类型 ClipData data = ClipData.newPlainText("dot", "Dot:" + v.toString()); /* * 开启拖动 * 第二个参数表示如果anr的类型为thumbnail(一小会儿),则让程序在6秒内无响应(休眠6秒) * 则无法完成阴影的绘制,该View不会响应拖动事件 * 第三个参数表示包含一些关于拖放操作数据的对象,在拖动过程中被系统发送到每一个拖放事件中 */ v.startDrag(data, new ANRShadowBuilder(v, mAnrType == ANR_SHADOW), (Object) v, 0); return true; } }); } public void setReportView(TextView view) { mReportTextView = view; } @Override protected void onDraw(Canvas canvas) { float wf = getWidth(); float hf = getHeight(); //System.out.println(wf); final float cx = wf / 2; final float cy = hf / 2; wf -= getPaddingLeft() + getPaddingRight(); hf -= getPaddingTop() + getPaddingBottom(); float rad = (wf < hf) ? wf / 2 : hf / 2; canvas.drawCircle(cx, cy, rad, mPaint); // 绘制文本 if (mLegend != null && mLegend.length() > 0) { canvas.drawText(mLegend, 0, mLegend.length(), cx, cy + mLegendPaint.getFontSpacing() / 2, mLegendPaint); } if (mDragInProgress && mAcceptsDrag) { for (int i = NUM_GLOW_STEPS; i > 0; i--) { // 当拖拽影子退出当前view时圆环为绿、白、红的渐变色; // 当拖拽影子退出当前view时圆环为白的渐变色; int color = (mHovering) ? WHITE_STEP : GREEN_STEP; color = i * (color | ALPHA_STEP); mGlow.setColor(color); canvas.drawCircle(cx, cy, rad, mGlow); rad -= 0.5f; canvas.drawCircle(cx, cy, rad, mGlow); rad -= 0.5f; } } } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { //System.out.println(getPaddingLeft()); //计算视图的宽和高 int totalDiameter=2*mRadius+getPaddingLeft()+getPaddingRight(); //System.out.println(totalDiameter); setMeasuredDimension(totalDiameter, totalDiameter); } @Override public boolean onDragEvent(DragEvent event) { boolean result=false; switch (event.getAction()) { case DragEvent.ACTION_DRAG_STARTED: Log.i(TAG, "Drag started, event=" + event); mDragInProgress=true; mAcceptsDrag=true; result=true; invalidate(); break; case DragEvent.ACTION_DRAG_ENDED: Log.i(TAG, "Drag ended"); if(mAcceptsDrag){ invalidate(); } mDragInProgress=false; mHovering=false; break; case DragEvent.ACTION_DRAG_LOCATION: //当View对象收到一个ACTION_DRAG_ENTERED事件之后,并且拖拽影子依然还在这个 //对象的边框之内时,这个View对象的拖拽事件监听器会接收这种事件操作类型 Log.i(TAG, "... seeing drag locations ..." ); result=mAcceptsDrag; break; case DragEvent.ACTION_DROP: //当View对象收到一个ACTION_DRAG_ENTERED事件之后,并且拖拽影子依然还在这个 //对象的边框之内时,这个View对象的拖拽事件监听器会接收这种事件操作类型 Log.i(TAG, "Got a drop! dot=" + this + " event=" + event ); if(mAnrType==ANR_DROP){ sleepSixSecond(); } processDrop(event); result=true; break; case DragEvent.ACTION_DRAG_ENTERED: Log.i(TAG, "Entered dot @ " + this ); mHovering=true; invalidate(); break; case DragEvent.ACTION_DRAG_EXITED: Log.i(TAG, "Exited dot @ " + this ); mHovering=false; invalidate(); break; default: Log.i(TAG, "other drag event: " + event); result=mAcceptsDrag; break; } return result; } private void processDrop(DragEvent event) { ClipData data=event.getClipData(); //获取剪贴板中条目的数量 int N=data.getItemCount(); for(int i=0;i<N;i++){ ClipData.Item item=data.getItemAt(i); Log.i(TAG, "Dropped item " + i + " : " + item); if(mReportTextView!=null){ //将条目的数据强制转化为文本 String text=item.coerceToText(getContext()).toString(); //如果拖动后在自己上面释放 if(event.getLocalState()==(Object)this){ text+=" : Dropped on self!"; } mReportTextView.setText(text); } } } }
activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:dot="http://schemas.android.com/apk/res/com.fisthosky.draggabledot" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#000000" android:orientation="vertical" > <TextView android:id="@+id/result_text" android:layout_width="match_parent" android:layout_height="wrap_content" android:textColor="#ffffffff" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" > <com.fisthosky.draganddrop.DraggableDot android:id="@+id/dot1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="15dp" dot:radius="64dp" /> <com.fisthosky.draganddrop.DraggableDot android:id="@+id/drag_dot2" android:layout_width="wrap_content" android:layout_height="wrap_content" dot:anr="thumbnail" android:padding="15dp" dot:legend="Drag ANR" dot:radius="64dp" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" > <com.fisthosky.draganddrop.DraggableDot android:id="@+id/drag_dot3" android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="15dp" dot:radius="64dp" dot:legend="Drop ANR" dot:anr= "drop"/> <com.fisthosky.draganddrop.DraggableDot android:id="@+id/drag_drag_hidden" android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="15dp" dot:radius="64dp" dot:legend="Surprise" android:visibility="invisible"/> </LinearLayout> <TextView android:id="@+id/drag_text" android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="5dp" android:textColor="#ffffff"/> </LinearLayout>
MainActivity
public class MainActivity extends Activity { private TextView mResultText; private DraggableDot mDragHidden; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); TextView textView=(TextView) findViewById(R.id.drag_text); DraggableDot dot; dot=(DraggableDot) findViewById(R.id.dot1); dot.setReportView(textView); dot=(DraggableDot) findViewById(R.id.drag_dot2); dot.setReportView(textView); dot=(DraggableDot) findViewById(R.id.drag_dot3); dot.setReportView(textView); mDragHidden=(DraggableDot) findViewById(R.id.drag_drag_hidden); mDragHidden.setReportView(textView); mResultText=(TextView) findViewById(R.id.result_text); //当拖放启动时系统会将拖放事件发送至每个view mResultText.setOnDragListener(new OnDragListener() { @Override public boolean onDrag(View v, DragEvent event) { int aciton=event.getAction(); switch (aciton) { case DragEvent.ACTION_DRAG_STARTED: mDragHidden.setVisibility(View.VISIBLE); break; case DragEvent.ACTION_DRAG_ENDED: mDragHidden.setVisibility(View.INVISIBLE); boolean dropped=event.getResult(); mResultText.setText(dropped ? "Dropped!" : "No drop"); break; default: break; } return false; } }); } }
相关文章推荐
- android开发之GPS定位详解
- Android-状态栏透明导致android:windowSoftInputMode属性失效
- live555移植到Android过程.
- 项目开发,我的名字不可能这么可爱——开篇
- Android 6.0的变化之权限管理
- Android静态代码检查-Lint
- [Android Pro] CPU占用计算方法
- Android SDK Android NDK Android Studio 官方下载地址
- android studio StackView控件的源码解释和简单示例
- android知乎小圆圈刷新效果
- Android 解决bug:异常提示"ListView cannot be cast to android.widget.BaseAdapter "
- 从源码中浅析Android中如何利用attrs和styles定义控件
- android.support.design.widget.TabLayout 用法解析
- Android 内存优化 (转载)
- Android 内存管理 &Memory Leak & OOM 分析
- Android ,TextView 设置onClick 没反应
- Anko for Android
- Android自定义控件之美观的实用型统计表的制作
- Android Studio中如何打JAR包
- 【转】Android截屏