Android Api Demos登顶之路(106)View-->DragAndDrop

这个demo演示了拖放功能的实现
同样使用了自定义属性和自定义视图
自定义属性: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;
            }
        });
    }


}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值