【问题标题】:How to create a custom drag shadow?如何创建自定义拖动阴影?
【发布时间】:2014-03-08 20:04:14
【问题描述】:

我想要达到的目标:

我想在 Android 中创建拖放功能。我想使用特定的布局(不同于被拖动对象本身)作为拖动阴影。

我得到了什么结果:

我的两种方法都没有按预期工作 - 我最终没有可见的拖动阴影(尽管目标确实收到了拖放)。

我尝试了什么:

我试过了

  • 在 Activity 中扩展 drag_item 布局,然后将其作为参数传递给影子构建器的构造函数

  • 在阴影生成器的onDrawShadow 方法中膨胀drag_item 布局,然后在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>

源代码:

这是两种方法的代码(分别由1BuilderOne2BuilderTwo 表示):

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);
            }
        }
    }
}

问题:

我做错了什么?

更新:

已添加赏金。

【问题讨论】:

    标签: android drag-and-drop


    【解决方案1】:

    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 视图并不是您想要的,但如果它有效,那么至少我们知道问题出在哪里,并且可以寻找解决方案!

    【讨论】:

    • 这是一些想法。也许我可以将它添加到用户看不到的地方(但仍然是布局的一部分)?它仍然是一个黑客,但如果它成功了......我回家后会试试
    • 另一个想法(以及我目前正在做我的自定义 DropShadow 的方式)是只使用View 来设置onDrawShadow 中使用的Canvas 的尺寸,然后重建在覆盖的onDrawShadow 中手动显示。您也许可以使用CharSequence text = ((TextView) getView()).getText() 访问存储在膨胀的View 中的文本,然后在Canvas.drawText() 中使用其结果
    • 这对你有帮助吗,@KonradMorawski?
    • 对不起。好吧,我没有时间深入挖掘,最终妥协了,取出拖动对象的部分并将其用作我的影子。足够好,但不是真正的自定义视图。您可能是正确的,根本问题是阴影只存在于抽象中,因此永远不会“实际”膨胀=没有维度。我没有尝试隐藏视图的技巧。我+1你的答案,因为它指向正确的方向,但我不能接受它,因为它不能完全回答问题,它有点像黑客。我仍然相信有一些适当的方法可以做到这一点。总之谢谢
    • 看来您可以将视图渲染为位图,然后使用位图实例化 DragShadowBuilder。将视图渲染为位图,如下所示:
    【解决方案2】:

    简单地说,你只需要这个:

    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 类)

    【讨论】:

    • 您的解决方案没有抓住重点。它会给我默认阴影(btnDragged 本身)。而不是dragged_item,我想用它来代替。
    猜你喜欢
    • 2020-09-20
    • 2020-09-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多