欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

图文混排发帖

程序员文章站 2022-04-25 07:50:40
...

图文混排发帖
(效果图为最终项目中的)

本文源码已经托管在GitHub上,欢迎Fork多多star。地址

最近重构一个项目,增加了一个新需求,要类似汽车之家的图文混排发帖,图片文字可*移动位置(如效果图)

功能:图文混排,*排列文字与图片的位置,图片之间自动加入输入框,两个输入框若相邻且有一个为空,则删除一个保留另外一个,若都有内容则不删除,删除文字时,若输入框内容为空,则删除整个输入框

实现:RecyclerView + ItemTouchHelper(为什么用RecyclerView,不用ListView,这个个人觉得RecyclerView的效果要比ListView好,汽车之家应该是ListView(猜测))

代码:
首先要改造一下ItemTouchHelper这个类,这是Android提供的拖拽帮助类,在android.support.v7.widget.helper包下。
改造的原因:
图文混排发帖

图中的Callback,在下面的处理过程中需要使用,但是他是protected的,所以我们要想要拿出来就要这样:
图文混排发帖

新建一个package 包名如图要一样,然后新建一个class 集成ItemTouchHelper这个类。

public class MosrItemTouchHelper extends ItemTouchHelper {
    public MosrItemTouchHelper(Callback callback) {
        super(callback);
    }

    public Callback getCallback() {
        return mCallback;
    }
}

加上get方法就可以了。

public class DefaultItemTouchHelper extends MosrItemTouchHelper {

    private DefaultItemTouchHelpCallback itemTouchHelpCallback;

    public DefaultItemTouchHelper(DefaultItemTouchHelpCallback.OnItemTouchCallbackListener onItemTouchCallbackListener) {
        super(new DefaultItemTouchHelpCallback(onItemTouchCallbackListener));
        itemTouchHelpCallback = (DefaultItemTouchHelpCallback) getCallback();
    }

    /**
     * 设置是否可以被拖拽
     *
     * @param canDrag 是true,否false
     */
    public void setDragEnable(boolean canDrag) {
        itemTouchHelpCallback.setDragEnable(canDrag);
    }

    /**
     * 设置是否可以被滑动
     *
     * @param canSwipe 是true,否false
     */
    public void setSwipeEnable(boolean canSwipe) {
        itemTouchHelpCallback.setSwipeEnable(canSwipe);
    }
}

这个类用户设置拖拽,滑动动作的可用性。

public class DefaultItemTouchHelpCallback extends ItemTouchHelper.Callback {

    /**
     * Item操作的回调
     */
    private OnItemTouchCallbackListener onItemTouchCallbackListener;

    /**
     * 是否可以拖拽
     */
    private boolean isCanDrag = false;
    /**
     * 是否可以被滑动
     */
    private boolean isCanSwipe = false;

    public DefaultItemTouchHelpCallback(OnItemTouchCallbackListener onItemTouchCallbackListener) {
        this.onItemTouchCallbackListener = onItemTouchCallbackListener;
    }

    /**
     * 设置Item操作的回调,去更新UI和数据源
     *
     * @param onItemTouchCallbackListener
     */
    public void setOnItemTouchCallbackListener(OnItemTouchCallbackListener onItemTouchCallbackListener) {
        this.onItemTouchCallbackListener = onItemTouchCallbackListener;
    }

    /**
     * 设置是否可以被拖拽
     *
     * @param canDrag 是true,否false
     */
    public void setDragEnable(boolean canDrag) {
        isCanDrag = canDrag;
    }

    /**
     * 设置是否可以被滑动
     *
     * @param canSwipe 是true,否false
     */
    public void setSwipeEnable(boolean canSwipe) {
        isCanSwipe = canSwipe;
    }

    /**
     * 当Item被长按的时候是否可以被拖拽
     *
     * @return
     */
    @Override
    public boolean isLongPressDragEnabled() {
        return isCanDrag;
    }

    /**
     * Item是否可以被滑动(H:左右滑动,V:上下滑动)
     *
     * @return
     */
    @Override
    public boolean isItemViewSwipeEnabled() {
        return isCanSwipe;
    }

    /**
     * 当用户拖拽或者滑动Item的时候需要我们告诉系统滑动或者拖拽的方向
     *
     * @param recyclerView
     * @param viewHolder
     *
     * @return
     */
    @Override
    public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
        RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
        if (layoutManager instanceof GridLayoutManager) {// GridLayoutManager
            // flag如果值是0,相当于这个功能被关闭
            int dragFlag = ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT | ItemTouchHelper.UP | ItemTouchHelper.DOWN;
            int swipeFlag = 0;
            // create make
            return makeMovementFlags(dragFlag, swipeFlag);
        } else if (layoutManager instanceof LinearLayoutManager) {// linearLayoutManager
            LinearLayoutManager linearLayoutManager = (LinearLayoutManager) layoutManager;
            int orientation = linearLayoutManager.getOrientation();

            int dragFlag = 0;
            int swipeFlag = 0;

            // 为了方便理解,相当于分为横着的ListView和竖着的ListView
            if (orientation == LinearLayoutManager.HORIZONTAL) {// 如果是横向的布局
                swipeFlag = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
                dragFlag = ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
            } else if (orientation == LinearLayoutManager.VERTICAL) {// 如果是竖向的布局,相当于ListView
                dragFlag = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
                swipeFlag = ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
            }
            return makeMovementFlags(dragFlag, swipeFlag);
        }
        return 0;
    }

    /**
     * 当Item被拖拽的时候被回调
     *
     * @param recyclerView     recyclerView
     * @param srcViewHolder    拖拽的ViewHolder
     * @param targetViewHolder 目的地的viewHolder
     *
     * @return
     */
    @Override
    public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder srcViewHolder, RecyclerView.ViewHolder targetViewHolder) {
        if (onItemTouchCallbackListener != null) {
            return onItemTouchCallbackListener.onMove(srcViewHolder.getAdapterPosition(), targetViewHolder.getAdapterPosition());
        }
        return false;
    }

    @Override
    public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
        if (onItemTouchCallbackListener != null) {
            onItemTouchCallbackListener.onSwiped(viewHolder.getAdapterPosition());
        }
    }

    public interface OnItemTouchCallbackListener {
        /**
         * 当某个Item被滑动删除的时候
         *
         * @param adapterPosition item的position
         */
        void onSwiped(int adapterPosition);

        /**
         * 当两个Item位置互换的时候被回调
         *
         * @param srcPosition    拖拽的item的position
         * @param targetPosition 目的地的Item的position
         *
         * @return 开发者处理了操作应该返回true,开发者没有处理就返回false
         */
        boolean onMove(int srcPosition, int targetPosition);
    }
}

这个类用户处理拖拽,滑动等动作。

接下来,创建一个RecyclerView布局,初始化,设置布局管理器,设置适配器,
加入如下代码


        // 把ItemTouchHelper和itemTouchHelper绑定
        itemTouchHelper = new DefaultItemTouchHelper(onItemTouchCallbackListener);
        itemTouchHelper.attachToRecyclerView(recyclerView);

        mainAdapter.setItemTouchHelper(itemTouchHelper);

        itemTouchHelper.setDragEnable(false);
        itemTouchHelper.setSwipeEnable(false);
    private DefaultItemTouchHelpCallback.OnItemTouchCallbackListener onItemTouchCallbackListener = new DefaultItemTouchHelpCallback.OnItemTouchCallbackListener() {
        @Override
        public void onSwiped(int adapterPosition) {
            if (userInfoList != null) {
                userInfoList.remove(adapterPosition);
                mainAdapter.notifyItemRemoved(adapterPosition);
            }
        }

        @Override
        public synchronized boolean onMove(int srcPosition, int targetPosition) {
            mSrcPosition = srcPosition;
            mTargetPosition = targetPosition;
            Log.e("mosr", "srcPosition: " + srcPosition);
            Log.e("mosr", "targetPosition: " + targetPosition);
            if (userInfoList != null) {
                // 更换数据源中的数据Item的位置
                Collections.swap(userInfoList, srcPosition, targetPosition);

                // 更新UI中的Item的位置,主要是给用户看到交互效果
                mainAdapter.notifyItemMoved(srcPosition, targetPosition);
                mSelectPostion = targetPosition;
                isMoveing = true;
                return true;
            }
            return false;
        }
    };

Adapter代码处理 指定View 设置onLongClickListener

    public void setHeight(int mHeight, RecyclerView.ViewHolder mViewHolder) {
        if (this.mHeight == mHeight)
            return;
        this.mHeight = mHeight;
        if (mHeight == 400)
            try {
                for (MainContentViewHolder viewHolder : mList) {
                    viewHolder.setData();
                }
            } catch (Exception e) {
            }
        else
            notifyDataSetChanged();
        mList.clear();
        if (null != mViewHolder)
            itemTouchHelper.startDrag(mViewHolder);

    }

!!!因为拖拽时需求让图片的高度减少,所以要动态设置图片View 的高度,上述代码可见变小时不是用notifyDataSetChanged 而是通过ViewHolder的SetDate方法,是因为notifyDataSetChanged 会重新绘制布局导致ItemToucHelper失去焦点,谨记!!!

当手离开屏幕时还原图片高度

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_MOVE:
                break;
            case MotionEvent.ACTION_UP:
                notifyItemView();
                mainAdapter.setHeight(700, null);
                break;
        }
        return false;
    }

处理图片之间的输入框,输入框与输入框之间的关系

    private void notifyItemView() {
        if (!isMoveing)
            return;
        try {
            if (userInfoList.get(0).getIsPic() != 1)//第一行
                userInfoList.add(0, new InvitationInfo("", "", 1));
            if (userInfoList.get(userInfoList.size() - 1).getIsPic() != 1) //最后一行
                userInfoList.add(new InvitationInfo("", "", 1));
            for (int i = 0; i < userInfoList.size(); i++) {
                if (i > 0 && userInfoList.get(i).getIsPic() == 0 && userInfoList.get(i).getIsPic() == userInfoList.get(i - 1).getIsPic()) {
                    userInfoList.add(i, new InvitationInfo("", "", 1));
                    mSelectPostion = mSelectPostion < i ? mSelectPostion : mSelectPostion++;
                    i++;
                }
            }

            for (int i = 0; i < userInfoList.size(); i++) {
                if (userInfoList.get(i).getIsPic() == 1 && i > 0 && userInfoList.get(i).getIsPic() == userInfoList.get(i - 1).getIsPic())
                    if (TextUtils.isEmpty(userInfoList.get(i).getText())) {
                        userInfoList.remove(i);
                        mSelectPostion = mSelectPostion < i ? mSelectPostion : mSelectPostion--;
                        i--;
                    } else if (TextUtils.isEmpty(userInfoList.get(i - 1).getText())) {
                        userInfoList.remove(i - 1);
                        mSelectPostion = mSelectPostion < i - 1 ? mSelectPostion : mSelectPostion--;
                        i--;
                    }
            }
        } catch (IndexOutOfBoundsException e) {
            e.printStackTrace();
        } finally {
            mainAdapter.notifyDataSetChanged();
            recyclerView.smoothScrollToPosition(mSelectPostion);
            isMoveing = false;
        }
    }

核心部分都在上面了,由于是调研时写的Demo 所以很多地方不严谨,逻辑不清晰,借鉴者多加留意,参考我在GitHub上托管的源码。
如有问题Q我1515789527