懒人式拖拉调换功能模块次序(适用GridView和RecyclerView)

前言

        首先说明,调整模块菜单次序,不是什么痛点功能。只是为了优化用户体验,这个东西,完全自定义拖拉式菜单也没有多大难点,但是作为一个懒人,还是遵从一点,能用google自带组件的,尽量用自带的,除非它真没有。

        所以这次就只是在GridView|RecyclerView的基础上,加上拖拉调换次序的功能。以应付日常开发需求。本次以GridView为样例,先上效果图。

步骤

   1.还是先梳理一下思路:

  • 当用户长按选择一个item时,将该item隐藏,然后用WindowManager添加一个新的window,该window与所选择item一模一样,并且跟随用户手指滑动而不断改变位置。
  • 当手指滑动到另一个item的位置的时候,将选择的item移出,并将此item插入到当前位置,选择的item在gridview中一直占位但不显示,因为你在windowManager创建的这个一模一样的item还在展示(否则就显示两个了)。
  • 当用户手指抬起时,把window移除,显示Gridview中你选择item,使用notifyDataSetChanged()做出GridView更新。

   2.代码部分:

  •       GridView的适配器,正常写,只是加入一些函数来处理滑动时候的事件。
public class BlockGridAdapter extends BaseAdapter {
    public static final int WAIT_POSITION = -101;
    public List<MainBean> mBlockList = new ArrayList<>();
    private final Context mContext;
    private LayoutInflater inflater;
    private int pullItemPosition = WAIT_POSITION;


    public BlockGridAdapter(Context context, List<MainBean> list) {
        mBlockList.clear();
        mBlockList.addAll(list);
        mContext = context;
        this.inflater = LayoutInflater.from(context);
    }


    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        //加载布局为一个视图
        View view = inflater.inflate(R.layout.item_grid_block, null);
        MainBean block = getItem(position);

        FrameLayout block_layout = view.findViewById(R.id.block_layout);
        TextView block_name = (TextView) view.findViewById(R.id.block_name);
        block_layout.setBackgroundResource(block.getBackgroundId());
        block_name.setText(block.getName());
        if (position == pullItemPosition) {
            block_layout.setVisibility(View.INVISIBLE);
        } else {
            block_layout.setVisibility(View.VISIBLE);
        }

        //返回含有数据的view
        return view;
    }


    @Override
    public int getCount() {
        return mBlockList.size();
    }

    @Override
    public MainBean getItem(int position) {
        return mBlockList.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    public void pull2Position(int newPosition) {
        if (newPosition < 0 || newPosition == pullItemPosition) {
            return;
        }

        int position = pullItemPosition;
        MainBean currBlock = getItem(position);
        remove(position);

        mBlockList.add(newPosition, currBlock);
        pullItemPosition = newPosition;
        notifyDataSetChanged();
    }

    public void pullStart(int position) {
        if (position < 0) {
            return;
        }

        pullItemPosition = position;
        notifyDataSetChanged();
    }

    public void pullFinish() {
        pullItemPosition = WAIT_POSITION;
        notifyDataSetChanged();
        saveBlockOrder();
    }

    private void remove(int position) {
        MainBean item = getItem(position);

        Iterator<MainBean> iterator = mBlockList.iterator();
        while (iterator.hasNext()) {
            MainBean bean = iterator.next();
            if (item.getFunctionId() == bean.getFunctionId()) {
                iterator.remove();
                break;
            }
        }
    }

    private void saveBlockOrder() {
       //保存次序位置
    }
}
  • 触屏部分
private void onGridTouchEvent() {
    mGvItemGrid.setOnTouchListener(this);
}

private WindowManager mWindowManager;
private WindowManager.LayoutParams mLayoutParams;

private void initWindowsManager() {
    mWindowManager = (WindowManager) getActivity().getSystemService(WINDOW_SERVICE);
    mLayoutParams = new WindowManager.LayoutParams();
    mLayoutParams.gravity = Gravity.START | Gravity.TOP;
    mLayoutParams.width = DensityUtil.dpToPx(getContext(), 120);
    mLayoutParams.height = DensityUtil.dpToPx(getContext(), 120);
}


private void addItemView(int x, int y, int position) {
    if (position < 0) {
        return;
    }

    mLayoutParams.x = x;
    mLayoutParams.y = y;
    Log.i(TAG, "addItemView: 坐标X = " + x);
    Log.i(TAG, "addItemView: 坐标Y = " + y);
    mFloatItemView = View.inflate(getContext(), R.layout.item_grid_block, null);
    MainBean bean = mGridAdapter.getItem(position);
    FrameLayout layout = mFloatItemView.findViewById(R.id.block_layout);
    TextView textView = mFloatItemView.findViewById(R.id.block_name);
    layout.setBackgroundResource(bean.getBackgroundId());
    textView.setText(bean.getName());
    mWindowManager.addView(mFloatItemView, mLayoutParams);
}

private void pullItemView(int x, int y) {
    mLayoutParams.x = x;
    mLayoutParams.y = y;
    mWindowManager.updateViewLayout(mFloatItemView, mLayoutParams);
}

private void removeItemView() {
    mWindowManager.removeView(mFloatItemView);
}


private float startX, startY;//起始点击位置
private int positionX, positionY;//起始显示位置

@Override
public boolean onTouch(View v, MotionEvent event) {
    float x = event.getX();
    float y = event.getY();
    int position = getGridViewPositionByPoint(mGvItemGrid, x, y);
    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            startX = x;
            startY = y;
            positionX = getItemX(position);
            positionY = getItemY(position);
            addItemView(positionX, positionY, position);
            mGridAdapter.pullStart(position);
            break;
        case MotionEvent.ACTION_MOVE:
            int plusX = (int) (x - startX);
            int plusY = (int) (y - startY);
            pullItemView(positionX + plusX, positionY + plusY);
            mGridAdapter.pull2Position(position);
            break;
        case MotionEvent.ACTION_UP:
            removeItemView();
            mGridAdapter.pullFinish();
            break;
        default:
            break;
    }

    return false;
}

private int getItemX(int position) {
    if (position < 0) {
        return 0;
    }
    View child = mGvItemGrid.getChildAt(position);
    return child.getLeft() + DensityUtil.dpToPx(getContext(), 40);//margin只设置了20,不知道这里为什么是40,可能是设置的间距造成的
}

private int getItemY(int position) {
    if (position < 0) {
        return 0;
    }
    View child = mGvItemGrid.getChildAt(position);
    return child.getTop() + DensityUtil.dpToPx(getContext(), 66);
}

public int getGridViewPositionByPoint(GridView gridView, float x, float y) {
    // 获取GridView的ChildCount
    int childCount = gridView.getChildCount();
    // 遍历子视图来找到点击的位置
    for (int i = 0; i < childCount; i++) {
        View child = gridView.getChildAt(i);
        // 获取子视图的坐标
        int left = child.getLeft();
        int top = child.getTop();
        int right = child.getRight();
        int bottom = child.getBottom();

        // 检查点击坐标是否在子视图的范围内
        if (x >= left && x <= right && y >= top && y <= bottom) {
            // 点击坐标在子视图范围内,返回position
            return i;
        }
        if (i == childCount - 1) {
            if (x >= left && y >= top) {
                return i;
            }
        }
    }
    // 没有找到对应的position,可能是点击在GridView之外
    return -1;
}

结尾

好了,基本上没费什么功夫,既不会影响和担心Gridview的性能,还基本实现了拖拉次序。效果也还不错。同理可以实现拖拉式RecyclerView。

以上,供您参考

参考文献:

带你一步步实现可拖拽的GridView控件 - 简书 (jianshu.com)

  • 28
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值