Как создать пользовательскую тень для трения?

Чего я хочу достичь:

Я хочу создать функцию перетаскивания в Android. Я хотел бы использовать конкретный макет (отличный от самого перетаскиваемого объекта) как тень перетаскивания.

Какой результат я получаю:

Ни один из моих подходов не работает так, как ожидалось. В конечном итоге у меня нет видимой теневой тени (хотя цель получает падение).

То, что я пробовал:

Я пытался

  • drag_item компоновку drag_item в активности, а затем передавая ее как аргумент конструктору теневого построителя

а также

  • drag_item макета onDrawShadow методе onDrawShadow теневого построителя, onDrawShadow затем рисование его на canvas

Макеты:

Мой макет деятельности:

 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/container" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.example.app.DragDropTestActivity" tools:ignore="MergeRootFrame"> <TextView android:id="@+id/tvReceiver" android:text="Drop here" android:layout_width="wrap_content" android:layout_height="wrap_content"/> <Button android:id="@+id/btnDragged" android:layout_height="wrap_content" android:text="Drag me" android:layout_width="match_parent"/> </LinearLayout> 

Макет, который я хочу использовать в качестве теневой тени:

dragged_item.xml

 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Dragged Item"/> </LinearLayout> 

Исходный код:

Вот код с обоими подходами (представленными 1 , BuilderOne и 2 , BuilderTwo , соответственно):

 package com.example.app; import android.graphics.Canvas; import android.graphics.Point; import android.os.Bundle; import android.support.v7.app.ActionBarActivity; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.widget.Button; public class DragDropTestActivity extends ActionBarActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_drag_drop_test); Button dragged = (Button) findViewById(R.id.btnDragged); dragged.setOnTouchListener( new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { if (event.getAction() != MotionEvent.ACTION_DOWN) { return false; } LayoutInflater inflater = getLayoutInflater(); int approach = 1; // both approaches fail switch (approach) { case 1: { View draggedItem = inflater.inflate(R.layout.dragged_item, null); BuilderOne builder = new BuilderOne(draggedItem); v.startDrag(null, builder, null, 0); break; } case 2: { BuilderTwo builder = new BuilderTwo(inflater, v); v.startDrag(null, builder, null, 0); break; } } return true; } }); } 

Мой класс BuilderOne :

  public static class BuilderOne extends View.DragShadowBuilder { public BuilderOne(View view) { super(view); } @Override public void onProvideShadowMetrics(Point shadowSize, Point shadowTouchPoint) { super.onProvideShadowMetrics( shadowSize, shadowTouchPoint); } } 

И класс BuilderTwo :

  public static class BuilderTwo extends View.DragShadowBuilder { final LayoutInflater inflater; public BuilderTwo(LayoutInflater inflater, View view) { super(view); this.inflater = inflater; } @Override public void onProvideShadowMetrics(Point shadowSize, Point shadowTouchPoint) { super.onProvideShadowMetrics( shadowSize, shadowTouchPoint); } @Override public void onDrawShadow(Canvas canvas) { final View draggedItem = inflater.inflate(R.layout.dragged_item, null); if (draggedItem != null) { draggedItem.draw(canvas); } } } } 

Вопрос:

Что я делаю неправильно?

Обновить:

Баунти добавила.

Kurty верен тем, что в этом случае вам не нужно подклассифицировать DragShadowBuilder . Моя мысль заключается в том, что представление, которое вы передаете в DragShadowBuilder , фактически не существует в макете, и поэтому оно не отображается.

Вместо того, чтобы передавать null в качестве второго аргумента для inflater.inflate , попробуйте фактически добавить раздутый View в иерархию где-нибудь, а затем передать его в обычный DragShadowBuilder :

 View dragView = findViewById(R.id.dragged_item); mDragShadowBuilder = new DragShadowBuilder(dragView); v.startDrag(null, mDragShadowBuilder, null, 0); 

РЕДАКТИРОВАТЬ

Я знаю, что наличие dragged_item все время не то, что вы хотите, но если оно работает, то, по крайней мере, мы знаем, где проблема, и можем искать решение для этого!

Проще говоря, вам нужно только это:

 private final class TouchListener implements View.OnTouchListener { @Override public boolean onTouch(View v, MotionEvent event) { if (event.getActionMasked() == MotionEvent.ACTION_DOWN) { v.startDrag(ClipData.newPlainText("", ""), new View.DragShadowBuilder(v), v, 0); } return true; } } 

(Вам не обязательно нужен класс BuilderOne и BuilderTwo)

Intereting Posts