简易频道拖拽功能实现及封装

最近看了视频学习了类似网易的频道拖动效果,就跟着敲了几遍,下面是总结和记录:

先看效果图,下图看不到的话,点击这里看效果

 

实现的效果:

1.点击按钮添加频道(gif没显示出来,但是有这个功能哈~)

2.长按按钮,实现textView的拖拽,原来的位置要有一个虚线为底的textview

3.当拖拽放到某个位置时,原来的位置的textVIew要删除掉,拖拽的textView放入当前位置。textView背景色恢复。

具体代码:代码中已经有较为详细的说明了,直接上~

java文件:

public class MyStuActivity extends AppCompatActivity {


    private Button button;
    private GridLayout layout;
    private View selectView;
    private List<Rect> rects;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_my_stu);
        button = findViewById(R.id.btn);
        layout = findViewById(R.id.layout_myGrid);

        /**
         * 在gridlayout中做拖拽监听
         */
        layout.setOnDragListener(new View.OnDragListener() {
            @Override
            public boolean onDrag(View v, DragEvent event) {
                switch (event.getAction()) {
                    case DragEvent.ACTION_DRAG_STARTED:
                        /**
                         * 开始拖拽,初始化矩形,这里面的每个矩形就是初始textview的位置,
                         * 利用矩形判断当前坐标是否在矩形内,如果再矩形内,就删除原来的textview,
                         * 并在当前位置添加拖拽的textView
                         */

                        initRects();
                        break;
                    case DragEvent.ACTION_DRAG_LOCATION:
                        //此部分是拖拽时的事件,只要在拖拽,就会一直响应此事件
                        int pos = isConstans(event);
                        if (pos > -1 && selectView != null && selectView != layout.getChildAt(pos)) {
                            //先删除原来的view
                            layout.removeView(selectView);
                            //添加显得veiw
                            layout.addView(selectView, pos);
                        }

                        break;
                    case DragEvent.ACTION_DRAG_ENDED:
                        //拖拽结束必定发生的事件,设置textview的背景
                        selectView.setEnabled(true);
                        break;
                }
                return true;
            }
        });

    }

    /**
     * 是否包含
     *
     * @param event
     * @return
     */
    private int isConstans(DragEvent event) {
        for (int i = 0; i < rects.size(); i++) {
            if (rects.get(i).contains((int) event.getX(), (int) event.getY())) {
                return i;
            }
        }
        return -1;
    }

    //初始化矩形
    private void initRects() {
        rects = new ArrayList<>();
        for (int i = 0; i < layout.getChildCount(); i++) {
            Rect rect = new Rect(layout.getChildAt(i).getLeft(), layout.getChildAt(i).getTop(),
                    layout.getChildAt(i).getRight(), layout.getChildAt(i).getBottom());

            rects.add(rect);

        }


    }

    //btn响应事件,点击添加一个textview
    public void addMyItem(final View view) {
        //添加一個子項
        int margin = 10;
        final TextView textView = new TextView(MyStuActivity.this);
        textView.setText("新闻");
        textView.setTextColor(getResources().getColor(R.color.colorBlack));
        textView.setGravity(Gravity.CENTER);
        //背景是一个选择器
        textView.setBackground(getResources().getDrawable(R.drawable.selector_tv));
        textView.setTextSize(20);
        textView.setPadding(margin, margin, margin, margin);
        //设置宽、高、margin时使用的layoutParams,注意此处的layoutParams必须是其父布局类型的layoutParams,
        //即必须使用GridLayout.LayoutParams
        GridLayout.LayoutParams layoutParams = new GridLayout.LayoutParams();
        layoutParams.setMargins(margin, margin, margin, margin);
        layoutParams.height = GridLayout.LayoutParams.WRAP_CONTENT;
        layoutParams.width = getResources().getDisplayMetrics().widthPixels / 4 - 2 * margin;
        layoutParams.setMargins(margin, margin, margin, margin);
        textView.setLayoutParams(layoutParams);

        textView.setOnLongClickListener(new View.OnLongClickListener() {
            @Override
            public boolean onLongClick(View v) {
                /**
                 * startDragAndDrop就是view的拖拽方法,他主要做了生成一个跟随鼠标拖动的控件视图。
                 */

                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                    textView.startDragAndDrop(null, new View.DragShadowBuilder(v),
                            null, 0);
                } else {
                    textView.startDrag(null, new View.DragShadowBuilder(v),
                            null, 0);
                }
                selectView = v;
                selectView.setEnabled(false);
                return false;
            }
        });

        layout.addView(textView, 0);

    }
}

xml内容:主要是设置gridlayout中列数,已经显示动画效果:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    android:orientation="vertical"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="app.study.com.mypindaostu20190123.MyStuActivity">

    <Button
        android:id="@+id/btn"
        android:text="添加"
        android:onClick="addMyItem"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <GridLayout
        android:columnCount="4"
        android:animateLayoutChanges="true"
        android:id="@+id/layout_myGrid"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"></GridLayout>
</LinearLayout>

textView的选择器代码:主要是设置了textView可不可用的属性,当可用/不可用的时候的背景

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_enabled="true" android:drawable="@drawable/shape_tv_nor"/>
    <item android:state_enabled="false" android:drawable="@drawable/shape_tv_sel"/>

</selector>

不用情况下的背景差不多,只是不可用的时候,背景边框是虚线而已,这里只贴下虚线的显示:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">

    <corners android:radius="5dp" />
    <solid android:color="#ffffff" />

    <!--dashGap是虚线的间隔-->
    <!--dashWidth是虚线的宽-->
    <stroke
        android:width="1dp"
        android:color="#f00"

        android:dashGap="2dp"
        android:dashWidth="1dp" />
</shape>

至此,初步完成,不知道为啥/**/的注释会变形,真心丑,还重新试了一下,还是老样子。。。

最后将其简单封装成类:

public class DragGridLayout extends GridLayout {

    //设置列数,默认4
    private int columnCount = 4;
    //控制是否长按可以拖拽
    private boolean canDrag;
    //被点击拖拽的视图
    private View selectView;
    //为每个textview画一个矩形
    private List<Rect> rects;


    public DragGridLayout(Context context) {
        this(context, null);
    }

    public DragGridLayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public DragGridLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initGridLayout();
    }

    //初始化gridlayout
    private void initGridLayout() {
        //设置最大列数啊
        this.setColumnCount(columnCount);
        //设置动画
        this.setLayoutTransition(new LayoutTransition());

    }

    //添加数据
    public void addItem(List<String> datas) {
        for (String data : datas) {
            //创建新的textView,将其添加进父布局中
            DragGridLayout.this.addView(newItem(data));
        }

    }

    //创建一个新的textview
    private TextView newItem(String data) {
        final TextView textView = new TextView(getContext());
        //设置边距
        int margin = 10;
        //设置textView的内容
        textView.setText(data);
        //设置文字颜色
        textView.setTextColor(getResources().getColor(R.color.colorBlack));
        //文字居中
        textView.setGravity(Gravity.CENTER);
        //背景是一个选择器
        textView.setBackground(getResources().getDrawable(R.drawable.selector_tv));
        //文字大小
        textView.setTextSize(20);
        //内边距
        textView.setPadding(margin, margin, margin, margin);
        //设置宽、高、margin时使用的layoutParams,注意此处的layoutParams必须是其父布局类型的layoutParams,
        //即必须使用GridLayout.LayoutParams
        GridLayout.LayoutParams layoutParams = new GridLayout.LayoutParams();
        layoutParams.setMargins(margin, margin, margin, margin);
        layoutParams.height = GridLayout.LayoutParams.WRAP_CONTENT;
        layoutParams.width = getResources().getDisplayMetrics().widthPixels / 4 - 2 * margin;
        layoutParams.setMargins(margin, margin, margin, margin);
        textView.setLayoutParams(layoutParams);

        if (this.canDrag) {
            textView.setOnLongClickListener(new View.OnLongClickListener() {
                @Override
                public boolean onLongClick(View v) {
                    /**
                     * startDragAndDrop就是view的拖拽方法,他主要做了生成一个跟随鼠标拖动的控件视图。
                     */
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                        textView.startDragAndDrop(null, new View.DragShadowBuilder(v),
                                null, 0);
                    } else {
                        textView.startDrag(null, new View.DragShadowBuilder(v),
                                null, 0);
                    }
                    selectView = v;
                    selectView.setEnabled(false);
                    return false;
                }
            });
        } else {
            textView.setOnLongClickListener(null);
        }
        return textView;
    }


    //初始化矩形坐标
    private void initRects() {
        rects = new ArrayList<>();
        for (int i = 0; i < DragGridLayout.this.getChildCount(); i++) {
            Rect rect = new Rect(DragGridLayout.this.getChildAt(i).getLeft(), DragGridLayout.this.getChildAt(i).getTop(),
                    DragGridLayout.this.getChildAt(i).getRight(), DragGridLayout.this.getChildAt(i).getBottom());
            //添加
            rects.add(rect);

        }
    }

    /**
     * 是否包含
     *
     * @param event
     * @return
     */
    private int isConstans(DragEvent event) {
        for (int i = 0; i < rects.size(); i++) {
            if (rects.get(i).contains((int) event.getX(), (int) event.getY())) {
                return i;
            }
        }
        return -1;
    }

    //设置是否可以长按拖拽
    public void setAllowDrag(boolean canDrag) {
        this.canDrag = canDrag;
        if (canDrag) {
            DragGridLayout.this.setOnDragListener(new OnDragListener() {
                @Override
                public boolean onDrag(View v, DragEvent event) {
                    switch (event.getAction()) {
                        case DragEvent.ACTION_DRAG_ENDED:
                            selectView.setEnabled(true);
                            break;
                        case DragEvent.ACTION_DRAG_STARTED:
                            initRects();
                            break;
                        case DragEvent.ACTION_DRAG_LOCATION:
                            //判断是否在当前的矩形内部
                            int pos = isConstans(event);
                            if (pos > -1 && selectView != null && selectView != DragGridLayout.this.getChildAt(pos)) {
                                //删除
                                DragGridLayout.this.removeView(selectView);
                                //添加
                                DragGridLayout.this.addView(selectView, pos);
                            }
                            break;
                    }
                    //此处需要返回true,说明成功处理了拖拽事件;
                    /**
                     * @return {@code true} if the drag event was handled successfully, or {@code false}
                     * if the drag event was not handled. Note that {@code false} will trigger the View
                     * to call its {@link #onDragEvent(DragEvent) onDragEvent()} handler.
                     */
                    return true;
                }
            });
        } else {
            DragGridLayout.this.setOnDragListener(null);
        }
    }
    
}

在java文件中的调用就很简单了:

dragGridLayout = (DragGridLayout) findViewById(R.id.layout_draggridlayout);
        List<String> datas = new ArrayList<>();
        datas.add("新闻");
        datas.add("娱乐");
        datas.add("体育");
        datas.add("科技");
        datas.add("社会");
        datas.add("明星");
        datas.add("八卦");
        datas.add("军事");
        datas.add("游戏");
        datas.add("时尚");
        datas.add("购物");
        datas.add("推文");
        //setAllowDrag需要在addItem前面设置!
        dragGridLayout.setAllowDrag(true);
        dragGridLayout.addItem(datas);

封装后的效果就是第一图的效果,没有button的。实现了textView的拖拽。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值