我对Android编程很陌生,现在我想了解有关拖放操作的更多信息。所以我的目标是将TextView拖到自定义按钮上,当我放下它时,TextView的Text应该替换Button的Text。 为此,我创建了一个“DropTargetView”,它扩展了Button:
public class DropTargetView extends Button implements View.OnDragListener{
private boolean mDropped;
public CharSequence name;
public DropTargetView(Context context) {
super(context);
init();
}
public DropTargetView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public DropTargetView(Context context, AttributeSet attrs, int defaultStyle) {
super(context, attrs, defaultStyle);
init();
}
private void init(){
setOnDragListener(this);
}
@Override
public boolean onDrag(View v, DragEvent event) {
PropertyValuesHolder pvhX, pvhY;
switch (event.getAction()){
case DragEvent.ACTION_DRAG_STARTED:
pvhX = PropertyValuesHolder.ofFloat("scaleX", 0.5f);
pvhY = PropertyValuesHolder.ofFloat("scaleY", 0.5f);
ObjectAnimator.ofPropertyValuesHolder(this,pvhX,pvhY).start();
mDropped = false;
break;
case DragEvent.ACTION_DRAG_ENDED:
pvhX = PropertyValuesHolder.ofFloat("scaleX", 1f);
pvhY = PropertyValuesHolder.ofFloat("scaleY", 1f);
ObjectAnimator.ofPropertyValuesHolder(this,pvhX,pvhY).start();
break;
case DragEvent.ACTION_DRAG_ENTERED:
pvhX = PropertyValuesHolder.ofFloat("scaleX", 0.75f);
pvhY = PropertyValuesHolder.ofFloat("scaleY", 0.75f);
ObjectAnimator.ofPropertyValuesHolder(this,pvhX,pvhY).start();
break;
case DragEvent.ACTION_DRAG_EXITED:
pvhX = PropertyValuesHolder.ofFloat("scaleX",0.5f);
pvhY = PropertyValuesHolder.ofFloat("scaleY", 0.5f);
ObjectAnimator.ofPropertyValuesHolder(this,pvhX,pvhY).start();
break;
case DragEvent.ACTION_DROP:
Keyframe frame0 = Keyframe.ofFloat(0f, 0.75f);
Keyframe frame1 = Keyframe.ofFloat(0.5f, 0f);
Keyframe frame2 = Keyframe.ofFloat(1f, 0.75f);
pvhX = PropertyValuesHolder.ofKeyframe("scaleX", frame0, frame1, frame2);
pvhY = PropertyValuesHolder.ofKeyframe("scaleY", frame0, frame1, frame2);
ObjectAnimator.ofPropertyValuesHolder(this, pvhX, pvhY).start();
name = (CharSequence) event.getLocalState();
setText(name);
mDropped = true;
break;
default:
return false;
}
return true;
}
}
然后我在我的XML文件中放了一堆这些按钮和我的TextView:
<TableLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="60dp"
android:id="@+id/tableLayout"
android:clickable="false"
android:theme="@android:style/DeviceDefault.Light.ButtonBar.AlertDialog">
<TableRow>
<com.example.scuba.dragdrop.DropTargetView
android:layout_weight="1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/btn1"
android:layout_margin="15dp"
android:text="1"
/>
<com.example.scuba.dragdrop.DropTargetView
android:layout_weight="1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="2"
android:id="@+id/btn2"
android:layout_margin="15dp"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="10"
android:id="@+id/Tv"
android:layout_below="@+id/tableLayout"
android:layout_centerHorizontal="true"
android:layout_marginTop="77dp" />
然后我长按TextView开始拖动动作:
public class WriteDigital extends AppCompatActivity implements View.OnLongClickListener {
public CharSequence value;
TextView Tv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_write_digital);
Tv = (TextView) findViewById(R.id.Tv);
Tv.setOnLongClickListener(this);
value = Tv.getText();
}
@Override
public boolean onLongClick(View v) {
DragShadowBuilder shadowBuilder = new DragShadowBuilder(v);
v.startDrag(null,shadowBuilder,value,0);
return false;
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_write_digital, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
所以当我开始拖动时,一切都很好并且动画效果很好。但是一旦我将TextView拖到按钮上,应用程序就崩溃了。我遇到了很多错误。有人说String无法在spannable中转换?
另外我想知道是否更好地使用Clip Data而不是Local state来传递文本信息以及我如何能够这样做? 希望有人可以提供帮助。
以下是我在logcat中的错误:
08-21 08:38:15.770 27274-27274/com.example.scuba.arduinoremote E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: com.example.scuba.arduinoremote, PID: 27274
java.lang.ClassCastException: java.lang.String cannot be cast to android.text.Spannable
at android.widget.TextView.onDragEvent(TextView.java:8767)
at android.view.View.dispatchDragEvent(View.java:17401)
at android.view.ViewGroup.dispatchDragEvent(ViewGroup.java:1249)
at android.view.ViewGroup.dispatchDragEvent(ViewGroup.java:1249)
at android.view.ViewGroup.dispatchDragEvent(ViewGroup.java:1249)
at android.view.ViewGroup.dispatchDragEvent(ViewGroup.java:1249)
at android.view.ViewGroup.dispatchDragEvent(ViewGroup.java:1249)
at android.view.ViewGroup.dispatchDragEvent(ViewGroup.java:1249)
at android.view.ViewGroup.dispatchDragEvent(ViewGroup.java:1249)
at android.view.ViewGroup.dispatchDragEvent(ViewGroup.java:1249)
at android.view.ViewRootImpl.handleDragEvent(ViewRootImpl.java:5026)
at android.view.ViewRootImpl.access$800(ViewRootImpl.java:96)
at android.view.ViewRootImpl$ViewRootHandler.handleMessage(ViewRootImpl.java:3213)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:149)
at android.app.ActivityThread.main(ActivityThread.java:5061)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:794)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:610)
at dalvik.system.NativeStart.main(Native Method)
答案 0 :(得分:0)
package com.vijay.dragdrop;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.os.IBinder;
import android.os.Vibrator;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.View;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager;
import java.util.ArrayList;
public class DragController
{
private static final String TAG = "DragController";
/** Indicates the drag is a move. */
public static int DRAG_ACTION_MOVE = 0;
/** Indicates the drag is a copy. */
public static int DRAG_ACTION_COPY = 1;
private static final int VIBRATE_DURATION = 35;
private static final boolean PROFILE_DRAWING_DURING_DRAG = false;
private Context mContext;
private Vibrator mVibrator;
private Rect mRectTemp = new Rect();
private final int[] mCoordinatesTemp = new int[2];
/** Whether or not we're dragging. */
private boolean mDragging;
/** X coordinate of the down event. */
private float mMotionDownX;
/** Y coordinate of the down event. */
private float mMotionDownY;
/** Info about the screen for clamping. */
private DisplayMetrics mDisplayMetrics = new DisplayMetrics();
/** Original view that is being dragged. */
private View mOriginator;
/** X offset from the upper-left corner of the cell to where we touched. */
private float mTouchOffsetX;
/** Y offset from the upper-left corner of the cell to where we touched. */
private float mTouchOffsetY;
/** Where the drag originated */
private DragSource mDragSource;
/** The data associated with the object being dragged */
private Object mDragInfo;
/** The view that moves around while you drag. */
private DragView mDragView;
/** Who can receive drop events */
private ArrayList<DropTarget> mDropTargets = new ArrayList<DropTarget>();
private DragListener mListener;
/** The window token used as the parent for the DragView. */
private IBinder mWindowToken;
private View mMoveTarget;
private DropTarget mLastDropTarget;
private InputMethodManager mInputMethodManager;
interface DragListener
{
void onDragStart(DragSource source, Object info, int dragAction);
void onDragEnd();
}
public DragController(Context context)
{
mContext = context;
mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
}
public void startDrag(View v, DragSource source, Object dragInfo, int dragAction)
{
boolean doDrag = source.allowDrag();
if (!doDrag)
return;
mOriginator = v;
Bitmap b = getViewBitmap(v);
if (b == null)
{
return;
}
int[] loc = mCoordinatesTemp;
v.getLocationOnScreen(loc);
int screenX = loc[0];
int screenY = loc[1];
startDrag(b, screenX, screenY, 0, 0, b.getWidth(), b.getHeight(), source, dragInfo, dragAction);
b.recycle();
if (dragAction == DRAG_ACTION_MOVE)
{
v.setVisibility(View.GONE);
}
}
public void startDrag(Bitmap b, int screenX, int screenY, int textureLeft, int textureTop, int textureWidth, int textureHeight, DragSource source, Object dragInfo, int dragAction)
{
if (PROFILE_DRAWING_DURING_DRAG)
{
android.os.Debug.startMethodTracing("Launcher");
}
if (mInputMethodManager == null)
{
mInputMethodManager = (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE);
}
mInputMethodManager.hideSoftInputFromWindow(mWindowToken, 0);
if (mListener != null)
{
mListener.onDragStart(source, dragInfo, dragAction);
}
int registrationX = ((int) mMotionDownX) - screenX;
int registrationY = ((int) mMotionDownY) - screenY;
mTouchOffsetX = mMotionDownX - screenX;
mTouchOffsetY = mMotionDownY - screenY;
mDragging = true;
mDragSource = source;
mDragInfo = dragInfo;
mVibrator.vibrate(VIBRATE_DURATION);
DragView dragView = mDragView = new DragView(mContext, b, registrationX, registrationY, textureLeft, textureTop, textureWidth, textureHeight);
dragView.show(mWindowToken, (int) mMotionDownX, (int) mMotionDownY);
}
private Bitmap getViewBitmap(View v)
{
v.clearFocus();
v.setPressed(false);
boolean willNotCache = v.willNotCacheDrawing();
v.setWillNotCacheDrawing(false);
int color = v.getDrawingCacheBackgroundColor();
v.setDrawingCacheBackgroundColor(0);
if (color != 0)
{
v.destroyDrawingCache();
}
v.buildDrawingCache();
Bitmap cacheBitmap = v.getDrawingCache();
if (cacheBitmap == null)
{
Log.e(TAG, "failed getViewBitmap(" + v + ")", new RuntimeException());
return null;
}
Bitmap bitmap = Bitmap.createBitmap(cacheBitmap);
v.destroyDrawingCache();
v.setWillNotCacheDrawing(willNotCache);
v.setDrawingCacheBackgroundColor(color);
return bitmap;
}
public boolean dispatchKeyEvent(KeyEvent event)
{
return mDragging;
}
public void cancelDrag()
{
endDrag();
}
private void endDrag()
{
if (mDragging)
{
mDragging = false;
if (mOriginator != null)
{
mOriginator.setVisibility(View.VISIBLE);
}
if (mListener != null)
{
mListener.onDragEnd();
}
if (mDragView != null)
{
mDragView.remove();
mDragView = null;
}
}
}
public boolean onInterceptTouchEvent(MotionEvent ev)
{
final int action = ev.getAction();
if (action == MotionEvent.ACTION_DOWN)
{
recordScreenSize();
}
final int screenX = clamp((int) ev.getRawX(), 0, mDisplayMetrics.widthPixels);
final int screenY = clamp((int) ev.getRawY(), 0, mDisplayMetrics.heightPixels);
switch (action)
{
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_DOWN:
mMotionDownX = screenX;
mMotionDownY = screenY;
mLastDropTarget = null;
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
if (mDragging)
{
drop(screenX, screenY);
}
endDrag();
break;
}
return mDragging;
}
void setMoveTarget(View view)
{
mMoveTarget = view;
}
public boolean dispatchUnhandledMove(View focused, int direction)
{
return mMoveTarget != null && mMoveTarget.dispatchUnhandledMove(focused, direction);
}
public boolean onTouchEvent(MotionEvent ev)
{
if (!mDragging)
{
return false;
}
final int action = ev.getAction();
final int screenX = clamp((int) ev.getRawX(), 0, mDisplayMetrics.widthPixels);
final int screenY = clamp((int) ev.getRawY(), 0, mDisplayMetrics.heightPixels);
switch (action)
{
case MotionEvent.ACTION_DOWN:
mMotionDownX = screenX;
mMotionDownY = screenY;
break;
case MotionEvent.ACTION_MOVE:
mDragView.move((int) ev.getRawX(), (int) ev.getRawY());
final int[] coordinates = mCoordinatesTemp;
DropTarget dropTarget = findDropTarget(screenX, screenY, coordinates);
if (dropTarget != null)
{
if (mLastDropTarget == dropTarget)
{
dropTarget.onDragOver(mDragSource, coordinates[0], coordinates[1], (int) mTouchOffsetX, (int) mTouchOffsetY, mDragView, mDragInfo);
}
else
{
if (mLastDropTarget != null)
{
mLastDropTarget.onDragExit(mDragSource, coordinates[0], coordinates[1], (int) mTouchOffsetX, (int) mTouchOffsetY, mDragView, mDragInfo);
}
dropTarget.onDragEnter(mDragSource, coordinates[0], coordinates[1], (int) mTouchOffsetX, (int) mTouchOffsetY, mDragView, mDragInfo);
}
}
else
{
if (mLastDropTarget != null)
{
mLastDropTarget.onDragExit(mDragSource, coordinates[0], coordinates[1], (int) mTouchOffsetX, (int) mTouchOffsetY, mDragView, mDragInfo);
}
}
mLastDropTarget = dropTarget;
break;
case MotionEvent.ACTION_UP:
if (mDragging)
{
drop(screenX, screenY);
}
endDrag();
break;
case MotionEvent.ACTION_CANCEL:
cancelDrag();
}
return true;
}
private boolean drop(float x, float y)
{
final int[] coordinates = mCoordinatesTemp;
DropTarget dropTarget = findDropTarget((int) x, (int) y, coordinates);
if (dropTarget != null)
{
dropTarget.onDragExit(mDragSource, coordinates[0], coordinates[1], (int) mTouchOffsetX, (int) mTouchOffsetY, mDragView, mDragInfo);
if (dropTarget.acceptDrop(mDragSource, coordinates[0], coordinates[1], (int) mTouchOffsetX, (int) mTouchOffsetY, mDragView, mDragInfo))
{
dropTarget.onDrop(mDragSource, coordinates[0], coordinates[1], (int) mTouchOffsetX, (int) mTouchOffsetY, mDragView, mDragInfo);
mDragSource.onDropCompleted((View) dropTarget, true);
return true;
}
else
{
mDragSource.onDropCompleted((View) dropTarget, false);
return true;
}
}
return false;
}
private DropTarget findDropTarget(int x, int y, int[] dropCoordinates)
{
final Rect r = mRectTemp;
final ArrayList<DropTarget> dropTargets = mDropTargets;
final int count = dropTargets.size();
for (int i = count - 1; i >= 0; i--)
{
final DropTarget target = dropTargets.get(i);
target.getHitRect(r);
target.getLocationOnScreen(dropCoordinates);
r.offset(dropCoordinates[0] - target.getLeft(), dropCoordinates[1] - target.getTop());
if (r.contains(x, y))
{
dropCoordinates[0] = x - dropCoordinates[0];
dropCoordinates[1] = y - dropCoordinates[1];
return target;
}
}
return null;
}
private void recordScreenSize()
{
((WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getMetrics(mDisplayMetrics);
}
private static int clamp(int val, int min, int max)
{
if (val < min)
{
return min;
}
else if (val >= max)
{
return max - 1;
}
else
{
return val;
}
}
public void setWindowToken(IBinder token)
{
mWindowToken = token;
}
public void setDragListener(DragListener l)
{
mListener = l;
}
public void removeDragListener(DragListener l)
{
mListener = null;
}
public void addDropTarget(DropTarget target)
{
mDropTargets.add(target);
}
public void removeDropTarget(DropTarget target)
{
mDropTargets.remove(target);
}
}
答案 1 :(得分:0)
似乎您正在使用setText()
您的代码应如下所示
setText(name, TextView.BufferType.SPANNABLE);