精华内容
下载资源
问答
  • layui 多图上传点击图片删除的实现与注意事项
    千次阅读
    2019-08-26 21:38:53

    layui的多图上传功能相当的方便。

    html:部分

    <div class="layui-form">
        <div class="layui-form-item">
            <label class="layui-form-label">活动图片:</label>
            <div class="layui-input-block">
                <div class="layui-upload">
                    <button type="button" class="layui-btn" id="uploadImgsBtn">
                        多图片上传
                    </button>
                    <div class="layui-upload-list" id="showUploadImgs"></div>
                </div>
            </div>
        </div>
    </div>

    文章已移至

     

    更多相关内容
  • 仿微信朋友圈发表图片拖拽和删除功能

              

    看这图片我们想到的是使用 RecyclerView 自带的ItemTouchHelper对拖拽进行处理,那先来一些知识的储备

    一:RecyclerView 的ItemTouchHelper

    官方解释:

    This is a utility class to add swipe to dismiss and drag & drop support to RecyclerView
    一个让 RecyclerView 支持滑动删除和拖拽的实用工具类

    主要方法

    //关联对应的 RecyclerView
    public void attachToRecyclerView(RecyclerView recyclerView)
    
    //viewHolder开始拖动
    public void startDrag(RecyclerView.ViewHolder viewHolder)
    
    //viewHolder开始滑动
    public void startSwipe(RecyclerView.ViewHolder viewHolder)
    

    使用

    • 自定义一个类继承并实现ItemTouchHelper.Callback接口,以下方法必须实现:
    //设置item是否处理拖拽事件和滑动事件,以及拖拽和滑动操作的方向
    @Override
    public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
    }
    
    //当用户从item原来的位置拖动可以拖动的item到新位置的过程中调用
    @Override
    public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
    }
    
    //滑动到消失后的调用
    @Override
    public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
    }
    • 实现化ItemTouchHelper并关联RecyclerView
    itemTouchHelper = new ItemTouchHelper(myCallBack);
    itemTouchHelper.attachToRecyclerView(recyclerView);

    二:ItemTouchHelper.Callback

    ItemTouchHelper在拖拽和滑动删除的过程中会回调ItemTouchHelper.Callback的相关方法

    主要方法

    //设置item是否处理拖拽事件和滑动事件,以及拖拽和滑动操作的方向
    public int getMovementFlags (RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder)
    
    /**
    *当用户从item原来的位置拖动可以拖动的item到新位置的过程中调用
    *@recyclerView 
    *@viewHolder 拖动的 item
    *@target 目标 item
    **/
    public boolean onMove (RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target)
    
    /**
    * RecyclerView调用onDraw时调用,如果想自定义item对用户互动的响应,可以重写该方法
    * @dx item 滑动的距离
    **/
    public void onChildDraw (Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive)
    
    //设置是否可以长按拖拽
    public boolean isLongPressDragEnabled ()
    
    //设置手指离开后ViewHolder的动画时间,在用户手指离开后调用
    public long getAnimationDuration(RecyclerView recyclerView, int animationType, float animateDx, float animateDy)
    
    //当长按选中item的时候(拖拽开始的时候)调用
    public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState)
    
    //当用户与item的交互结束并且item也完成了动画时调用
    public void clearView (RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder)

    三:实现过程

    1:从布局入手

    对应的xml布局如下:

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout 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"
        android:background="@color/white"
        android:focusableInTouchMode="true"
        android:orientation="vertical"
        tools:context=".module.feedback.add.FeedBackAddActivity">
    
    
        <androidx.core.widget.NestedScrollView
            android:id="@+id/scrollView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:fillViewport="true">
    
    
            <RelativeLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:clipChildren="false"
                android:clipToPadding="false">
    
                <com.snxun.zzypt.module.feedback.layout.EditTextWithScrollView
                    android:id="@+id/feedback_content_edit"
                    android:layout_width="match_parent"
                    android:layout_height="130dp"
                    android:autofillHints="@string/feedback_msg"
                    android:background="@null"
                    android:gravity="start"
                    android:hint="@string/feedback_msg"
                    android:inputType="textMultiLine"
                    android:maxLength="200"
                    android:paddingStart="20dp"
                    android:paddingTop="14dp"
                    android:paddingEnd="20dp"
                    android:paddingBottom="14dp"
                    android:textColor="@color/color_d9000000"
                    android:textColorHint="@color/color_40000000"
                    android:textSize="16sp" />
    
                <LinearLayout
                    android:id="@+id/bottom_ll"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginStart="20dp"
                    android:layout_marginTop="280dp"
                    android:layout_marginEnd="20dp"
                    android:orientation="vertical"
                    android:paddingBottom="15dp">
    
                    <View
                        android:layout_width="match_parent"
                        android:layout_height="1dp"
                        android:background="@color/color_17000000" />
    
                    <TextView
                        android:id="@+id/feedback_history_tv"
                        android:layout_width="match_parent"
                        android:layout_height="50dp"
                        android:drawablePadding="5dp"
                        android:gravity="center_vertical"
                        android:text="@string/feedback_history"
                        android:textColor="@color/color_d9000000"
                        android:textSize="14sp"
                        app:drawableEndCompat="@drawable/ic_right"
                        app:drawableStartCompat="@drawable/ic_history" />
    
                    <View
                        android:layout_width="match_parent"
                        android:layout_height="1dp"
                        android:background="@color/color_17000000" />
                </LinearLayout>
    
                <androidx.recyclerview.widget.RecyclerView
                    android:id="@+id/pic_rv"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_below="@+id/feedback_content_edit"
                    android:layout_marginStart="20dp"
                    android:layout_marginEnd="20dp"
                    android:nestedScrollingEnabled="false"
                    app:layoutManager="androidx.recyclerview.widget.StaggeredGridLayoutManager"
                    app:spanCount="3" />
    
            </RelativeLayout>
        </androidx.core.widget.NestedScrollView>
    
        <LinearLayout
            android:id="@+id/delete_area_view"
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:layout_alignParentBottom="true"
            android:layout_centerHorizontal="true"
            android:background="@color/color_FFF5222D"
            android:gravity="center"
            android:visibility="invisible">
    
            <TextView
                android:id="@+id/delete_area_tv"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:drawablePadding="5dp"
                android:gravity="center"
                android:text="@string/delete_pic"
                android:textColor="@color/white"
                app:drawableStartCompat="@drawable/ic_delete_white" />
        </LinearLayout>
    
    </RelativeLayout>

    EditTextWithScrollView这个类:

    我们设置输入框的高度是固定的,当输入的内容高于设置的高度时可进行滚动查看,用于解决嵌套Scrollview的时候由于多行而产生的滑动冲突问题,

    import android.content.Context;
    import android.util.AttributeSet;
    import android.view.MotionEvent;
    
    import androidx.appcompat.widget.AppCompatEditText;
    
    /**
     * 用于解决嵌套Scrollview的时候由于多行而产生的滑动冲突问题
     *
     * @author Wuczh
     * @date 2021/11/30
     */
    public class EditTextWithScrollView extends AppCompatEditText {
    
        //滑动距离的最大边界
        private int mOffsetHeight;
    
        //是否到顶或者到底的标志
        private boolean mBottomFlag = false;
        private boolean mCanVerticalScroll;
    
        public EditTextWithScrollView(Context context) {
            super(context);
            init();
        }
    
        public EditTextWithScrollView(Context context, AttributeSet attrs) {
            super(context, attrs);
            init();
        }
    
        public EditTextWithScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            init();
        }
    
        private void init() {
        }
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            mCanVerticalScroll = canVerticalScroll();
        }
    
        @Override
        public boolean dispatchTouchEvent(MotionEvent event) {
            if (event.getAction() == MotionEvent.ACTION_DOWN)
                //如果是新的按下事件,则对mBottomFlag重新初始化
                mBottomFlag = false;
            //如果已经不要这次事件,则传出取消的信号,这里的作用不大
            if (mBottomFlag)
                event.setAction(MotionEvent.ACTION_CANCEL);
    
            return super.dispatchTouchEvent(event);
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            boolean result = super.onTouchEvent(event);
            if (mCanVerticalScroll) {
                //如果是需要拦截,则再拦截,这个方法会在onScrollChanged方法之后再调用一次
                if (!mBottomFlag)
                    getParent().requestDisallowInterceptTouchEvent(true);
            } else {
                getParent().requestDisallowInterceptTouchEvent(false);
            }
            return result;
        }
    
        @Override
        protected void onScrollChanged(int horiz, int vert, int oldHoriz, int oldVert) {
            super.onScrollChanged(horiz, vert, oldHoriz, oldVert);
            if (vert == mOffsetHeight || vert == 0) {
                //这里触发父布局或祖父布局的滑动事件
                getParent().requestDisallowInterceptTouchEvent(false);
                mBottomFlag = true;
            }
        }
    
        /**
         * EditText竖直方向是否可以滚动
         *
         * @return true:可以滚动   false:不可以滚动
         */
        private boolean canVerticalScroll() {
            //滚动的距离
            int scrollY = getScrollY();
            //控件内容的总高度
            int scrollRange = getLayout().getHeight();
            //控件实际显示的高度
            int scrollExtent = getHeight() - getCompoundPaddingTop() - getCompoundPaddingBottom();
            //控件内容总高度与实际显示高度的差值
            mOffsetHeight = scrollRange - scrollExtent;
    
            if (mOffsetHeight == 0) {
    
                return false;
            }
    
            return (scrollY > 0) || (scrollY < mOffsetHeight - 1);
        }
    }

     三个属性的使用

    android:clipChildren="false"
     android:clipToPadding="false"
     android:fillViewport="true"

    Android开发实战(二十一):浅谈android:clipChildren属性 - 云+社区 - 腾讯云

    android:clipToPadding的使用_wangjiang-CSDN博客_android cliptopadding

    ScrollView中添加一个android:fillViewport="true"_Jsoh的博客-CSDN博客_android fillviewport

    设置RecyclerView的高度为android:layout_height="wrap_content",要想item可以在整个布局拖动,我们设置父布局RelativeLayout为

     <RelativeLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:clipChildren="false"
                android:clipToPadding="false">

    这样设置能实现全局拖动的效果吗?我们来看下下面的效果,发现item只可在父布局的范围内拖动,这时候需要我们将NestedScrollView加上属性fillViewport="true",这样RelativeLayout就可填充NestedScrollView,也就是全屏

     <androidx.core.widget.NestedScrollView
            android:id="@+id/scrollView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:fillViewport="true">

    下方显示的布局的设置:

    以一般的判断我们会将底下布局,直接在代码里设置相对与RecyclerView底部显示,那看下如果这样设置会出现什么情况:

     从图中可以看到,在移动item的时候,下面布局的显示位置会发生错乱,所以我们采用的是具体的显示位置在代码中进行位置计算后设置的。具体的计算我们在后面进行说明。

    2:设置ItemTouchHelperCallback继承ItemTouchHelper.Callback

    具体的实现在代码中都有很详细的备注

    import android.graphics.Canvas;
    
    import androidx.annotation.NonNull;
    import androidx.core.widget.NestedScrollView;
    import androidx.recyclerview.widget.ItemTouchHelper;
    import androidx.recyclerview.widget.RecyclerView;
    import androidx.recyclerview.widget.StaggeredGridLayoutManager;
    
    import com.lodz.android.corekt.album.PicInfo;
    import com.lodz.android.corekt.anko.AnkoAnimKt;
    import com.lodz.android.corekt.anko.AnkoArrayKt;
    import com.lodz.android.corekt.anko.AnkoDimensionsKt;
    import com.lodz.android.corekt.anko.AnkoVibratorKt;
    import com.snxun.zzypt.App;
    import com.snxun.zzypt.module.feedback.add.adapter.PhotoPublishAdapter;
    
    import java.util.ArrayList;
    import java.util.Collections;
    
    /**
     * 拖拽排序删除
     *
     * @author Wuczh
     * @date 2021/11/18
     */
    public class ItemTouchHelperCallback extends ItemTouchHelper.Callback {
    
        /**
         * 是否需要拖拽震动提醒
         */
        private boolean isNeedDragVibrate = true;
        /**
         * 适配器
         */
        private PhotoPublishAdapter mAdapter;
    
        /**
         * 手指抬起标记位
         */
        private boolean up;
        /**
         * 可滑动伸缩空间
         */
        private NestedScrollView mScrollView;
        /**
         * 数据列表
         */
        private ArrayList<PicInfo> mDataList;
    
        private int dragFlags;
        private int swipeFlags;
    
        /**
         * @param isNeedDragVibrate 是否需要拖拽震动提醒
         * @param imagesList        图片数据
         * @param scrollView        可滑动伸缩空间
         * @param adapter           适配器
         */
        public ItemTouchHelperCallback(boolean isNeedDragVibrate, ArrayList<PicInfo> imagesList, NestedScrollView scrollView, PhotoPublishAdapter adapter) {
            this.isNeedDragVibrate = isNeedDragVibrate;
            mAdapter = adapter;
            mScrollView = scrollView;
            mDataList = imagesList;
        }
    
        /**
         * 设置item是否处理拖拽事件和滑动事件,以及拖拽和滑动操作的方向
         */
        @Override
        public int getMovementFlags(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
            //判断 recyclerView的布局管理器数据,设置 item 只能处理拖拽事件,并能够向左、右、上、下拖拽
            if (recyclerView.getLayoutManager() instanceof StaggeredGridLayoutManager) {//设置能拖拽的方向
                dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
                swipeFlags = 0;//0则不响应滑动事件
            }
            return makeMovementFlags(dragFlags, swipeFlags);
        }
    
        /**
         * 拖拽,交换位置(当用户从item原来的位置拖动可以拖动的item到新位置的过程中调用)
         *
         * @param viewHolder 拖动的 item
         * @param target     目标 item
         */
        @Override
        public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder
                viewHolder, @NonNull RecyclerView.ViewHolder target) {
            if (AnkoArrayKt.isNullOrEmpty(mDataList)) {
                return false;
            }
            // 得到拖动ViewHolder的Position
            int fromPosition = viewHolder.getBindingAdapterPosition();
            // 得到目标ViewHolder的Position
            int toPosition = target.getBindingAdapterPosition();
    
            //因为没有将 +号的图片 加入imageList,所以不用imageList.size-1 此处限制不能移动到recyclerView最后一位
            if (toPosition == mDataList.size() || mDataList.size() == fromPosition) {
                return false;
            }
    
            if (fromPosition < toPosition) {//顺序小到大
                for (int i = fromPosition; i < toPosition; i++) {
                    Collections.swap(mDataList, i, i + 1);
                }
            } else {//顺序大到小
                for (int i = fromPosition; i > toPosition; i--) {
                    Collections.swap(mDataList, i, i - 1);
                }
            }
            mAdapter.notifyItemMoved(fromPosition, toPosition);
            return true;
        }
    
        /**
         * 滑动
         */
        @Override
        public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
        }
    
        /**
         * 当长按选中item时(拖拽开始时)调用
         * ItemTouchHelper.ACTION_STATE_IDLE  闲置状态
         * ItemTouchHelper.ACTION_STATE_DRAG  拖拽中状态
         */
        @Override
        public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
            if (viewHolder == null) {
                return;
            }
            //设置拖拽震动提醒
            if (actionState != ItemTouchHelper.ACTION_STATE_IDLE && isNeedDragVibrate) {
                AnkoVibratorKt.createVibrator(App.getInstance(), 100);
            }
            //设置拖拽动画
            if (actionState == ItemTouchHelper.ACTION_STATE_DRAG) {//开始拖拽
                AnkoAnimKt.startScaleSelf(viewHolder.itemView, 1.0f, 1.05f, 1.0f, 1.05f, 50, true);
            }
            //设置拖拽状态为true
            if (ItemTouchHelper.ACTION_STATE_DRAG == actionState && dragListener != null) {
                dragListener.dragState(true);
            }
            super.onSelectedChanged(viewHolder, actionState);
        }
    
        /**
         * 当手指松开时(拖拽完成时)调用
         * 在clearView()方法里去notifyDataSetChanged,不然 item的position是没有交换的
         */
        @Override
        public void clearView(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
            AnkoAnimKt.startScaleSelf(viewHolder.itemView, 1.05f, 1.0f, 1.05f, 1.0f, 50, true);
            super.clearView(recyclerView, viewHolder);
            initData();
            if (dragListener != null) {
                dragListener.clearView();
            }
        }
    
        /**
         * 自定义拖动与滑动交互
         *
         * @param c
         * @param recyclerView
         * @param viewHolder
         * @param dX                X轴移动的距离
         * @param dY                Y轴移动的距离
         * @param actionState       当前Item的状态
         * @param isCurrentlyActive 如果当前被用户操作为true,反之为false
         */
        @Override
        public void onChildDraw(Canvas c, @NonNull RecyclerView
                recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, float dX, float dY,
                                int actionState, boolean isCurrentlyActive) {
            if (null == dragListener) {
                return;
            }
            int editTextHeight = AnkoDimensionsKt.dp2px(App.getInstance(), 130);//输入框的高度
            int deleteViewHeight = AnkoDimensionsKt.dp2px(App.getInstance(), 50);//删除区间的高度
            /**
             *滑动的距离到达删除区域时的判断
             */
            if (dY >= (mScrollView.getHeight() - editTextHeight)
                    - viewHolder.itemView.getBottom()//item底部距离recyclerView顶部高度
                    - deleteViewHeight
                    + mScrollView.getScrollY()) {//拖到删除处
                dragListener.deleteState(true);
                if (up) {//在删除处放手,则删除item
                    mDataList.remove(viewHolder.getBindingAdapterPosition());
                    dragListener.deleteOk();
                    mAdapter.notifyDataSetChanged();
                    initData();
                    return;
                }
            } else {//没有到删除处
                dragListener.deleteState(false);
            }
            super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
        }
    
        /**
         * 设置是否支持长按拖拽
         * 此处必须返回false
         * 需要在recyclerView长按事件里限制,否则最后+号长按后扔可拖拽
         */
        @Override
        public boolean isLongPressDragEnabled() {
            return false;
        }
    
        /**
         * 设置是否支持支持滑动
         *
         * @return true  支持滑动操作
         * false 不支持滑动操作
         */
        @Override
        public boolean isItemViewSwipeEnabled() {
            return false;
        }
    
        /**
         * 设置手指离开后ViewHolder的动画时间,在用户手指离开后调用
         *
         * @param recyclerView
         * @param animationType
         * @param animateDx
         * @param animateDy
         * @return
         */
        @Override
        public long getAnimationDuration(@NonNull RecyclerView recyclerView, int animationType,
                                         float animateDx, float animateDy) {
            //手指放开
            up = true;
            return super.getAnimationDuration(recyclerView, animationType, animateDx, animateDy);
        }
    
        public interface DragListener {
            /**
             * 用户是否将 item拖动到删除处,根据状态改变颜色
             *
             * @param delete
             */
            void deleteState(boolean delete);
    
            /**
             * 是否于拖拽状态
             *
             * @param start
             */
            void dragState(boolean start);
    
            /**
             * 当删除完成后调用
             */
            void deleteOk();
    
            /**
             * 当用户与item的交互结束并且item也完成了动画时调用
             */
            void clearView();
        }
    
        private DragListener dragListener;
    
        public void setDragListener(DragListener dragListener) {
            this.dragListener = dragListener;
        }
    
        /**
         * 重置状态(拖拽状态设置为false 删除状态为false)
         */
        private void initData() {
            if (dragListener != null) {
                dragListener.deleteState(false);
                dragListener.dragState(false);
            }
            up = false;
        }
    }
    
    • 重点是实现拖拽到底部放手删除功能

    item从拖动到放手的主要处理流程图如下;

    那么我们应该在哪个地方去判断item是否到达删除区域呢?在前面介绍的方法,有这么个方法:onChildDraw,这个方法就会在item拖拽的过程不断回调并且返回item的偏移量。有了偏移量之后我们就很容易去判断item是否到达删除区域了。


    偏移量满足以下条件时,就到达删除区域:
    item偏移量>=RecyclerView的高-item底部到RecyclerView顶边的距离-.EditText的高+ScrollView.getScrollY()的滑动距离

    从上面的图片看起来,似乎没有体现ScrollView.getScrollY()的高度。可以观察下视频里的滑动效果,视频里是没有加上ScrollView.getScrollY()的高度的判断,发现在整个屏幕没有往上滑动的时候,item进行删除都是会到达删除区域的时候,但当我们把界面手动上划的时候发现item还没到达删除区域就会进入删除状态,这其实是dY的这个距离是包含ScrollView.getScrollY()的高度。

    视频效果滑动效果-CSDN直播

    • 怎样判断用户在拖动后放手呢?

    用boolean up来标记,当up为true时手指抬起,false为初始状态。在getAnimationDuration()中设置其为true。记得需要在clearView()中恢复初始值false;
    还需要在ItemTouchHelper.Callback中暴露个接口DragListener给外部,用来提示通知外部什么时候显示删除区域,以及item进入删除区域时的文字提示。

      /**
         * 设置手指离开后ViewHolder的动画时间,在用户手指离开后调用
         *
         * @param recyclerView
         * @param animationType
         * @param animateDx
         * @param animateDy
         * @return
         */
        @Override
        public long getAnimationDuration(@NonNull RecyclerView recyclerView, int animationType,
                                         float animateDx, float animateDy) {
            //手指放开
            up = true;
            return super.getAnimationDuration(recyclerView, animationType, animateDx, animateDy);
        }
    
    
    
     /**
         * 当手指松开时(拖拽完成时)调用,重置状态
         */
        @Override
        public void clearView(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
            AnkoAnimKt.startScaleSelf(viewHolder.itemView, 1.05f, 1.0f, 1.05f, 1.0f, 50, true);
            super.clearView(recyclerView, viewHolder);
            initData();
            if (dragListener != null) {
                dragListener.clearView();
            }
        }
    
     /**
         * 重置状态(拖拽状态设置为false 删除状态为false)
         */
        private void initData() {
            if (dragListener != null) {
                dragListener.deleteState(false);
                dragListener.dragState(false);
            }
            up = false;
        }
    
    
    
      /**
         * 自定义拖动与滑动交互
         *
         * @param c
         * @param recyclerView
         * @param viewHolder
         * @param dX                X轴移动的距离
         * @param dY                Y轴移动的距离
         * @param actionState       当前Item的状态
         * @param isCurrentlyActive 如果当前被用户操作为true,反之为false
         */
        @Override
        public void onChildDraw(Canvas c, @NonNull RecyclerView
                recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, float dX, float dY,
                                int actionState, boolean isCurrentlyActive) {
            if (null == dragListener) {
                return;
            }
            int editTextHeight = AnkoDimensionsKt.dp2px(App.getInstance(), 130);//输入框的高度
            int deleteViewHeight = AnkoDimensionsKt.dp2px(App.getInstance(), 50);//删除区间的高度
            /**
             * scrollView.getHeight()-editTextHeight 为recyclerview的高度
             * 此处不用onChildDraw里的参数recyclerView.getHeight来计算,因为当添加图片至超出屏幕高度
             * 即scrollView可以滑动后获取的recyclerview不准确,亲测。
             */
            if (dY >= (mScrollView.getHeight() - editTextHeight)
                    - viewHolder.itemView.getBottom()//item底部距离recyclerView顶部高度
                    - deleteViewHeight
                    + mScrollView.getScrollY()) {//拖到删除处
                dragListener.deleteState(true);
                if (up) {//在删除处放手,则删除item
                    mDataList.remove(viewHolder.getBindingAdapterPosition());
                    dragListener.deleteOk();
                    mAdapter.notifyDataSetChanged();
                    initData();
                    return;
                }
            } else {//没有到删除处
                dragListener.deleteState(false);
            }
            super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
        }

    3. 关联 RecyclerView

      ItemTouchHelperCallback myCallBack = new ItemTouchHelperCallback(false, mDataList, mBinding.scrollView, mAdapter);
      mItemTouchHelper = new ItemTouchHelper(myCallBack);//实现化ItemTouchHelper(拖拽和滑动删除的过程中会回调ItemTouchHelper.Callback的相关方法)
      mItemTouchHelper.attachToRecyclerView(mBinding.picRv);//关联对应的 RecyclerView
      //滑动状态回调处理
            myCallBack.setDragListener(new ItemTouchHelperCallback.DragListener() {
                @Override
                public void deleteState(boolean delete) {
                    //根据是否是删除状态,显示对应的删除区域的文字和背景色
                    if (delete) {
                        mBinding.deleteAreaView.setAlpha(0.9f);
                        mBinding.deleteAreaTv.setText(getString(R.string.loosen_delete_pic));
                    } else {
                        mBinding.deleteAreaView.setAlpha(0.6f);
                        mBinding.deleteAreaTv.setText(R.string.drag_delete_pic);
                    }
                }
    
                @Override
                public void dragState(boolean start) {
                    //根据是否是开始滑动状态,来设置是否显示删除区域
                    if (start) {
                        mBinding.deleteAreaView.setVisibility(View.VISIBLE);
                    } else {
                        mBinding.deleteAreaView.setVisibility(View.GONE);
                    }
                }
    
                @Override
                public void deleteOk() {
                    //删除后重新计算图片选择数量
    
                }
    
                @Override
                public void clearView() {
                    //item删除后需要重新计算底部区域的显示位置,否则会造成底部区域显示混乱
                    fixBottom();
                }
            });

    4:注意需设置加号不能进行拖拽

    由以上分析可知,ItemTouchHelper.Callback的isLongPressDragEnabled()可以设置是否支持长按拖拽,默认是true,即支持长按拖拽。现在我们要自定义指定哪些item可以拖拽,哪些不可以,因此我们需要重写isLongPressDragEnabled()

        /**
         * 设置是否支持长按拖拽
         * 此处必须返回false
         * 需要在recyclerView长按事件里限制,否则最后+号长按后扔可拖拽
         */
        @Override
        public boolean isLongPressDragEnabled() {
            return false;
        }

    item的长按事件中进行是否拖动判断,这边的长按有两种方式,一种是在Adapter适配器中对item的长按事件进行监听回调,还有一种方式是自定义RecyclerView 的点击监听事件,可以参考以下内容:RecyclerView的高效触摸监听 - 简书,至于哪种方式看大家自己选择,这边用前者进行讲解。

            主要就是在自己设置的长按回调里进行是否拖拽的操作!

     
            @Override
            public void onItemLongClick(RecyclerView.ViewHolder viewHolder) {
              //我这边是因为当position==数据数量时就是加号图片,这里要看实际的值进行设置
                if (viewHolder.getBindingAdapterPosition() != mDataList.size()) {
                        mItemTouchHelper.startDrag(viewHolder);//viewHolder开始拖动
                    }
            }
       
    

    5:在代码中计算底部区域的显示位置

        /**
         * 处理recyclerView下面的布局
         */
        private void fixBottom() {
            int row = mAdapter.getItemCount() / 3;
            row = (0 == mAdapter.getItemCount() % 3) ? row : row + 1;//少于3为1行
            int screenWidth = AnkoScreenKt.getScreenWidth(getContext());
            int itemHeight = (screenWidth - AnkoDimensionsKt.dp2px(getContext(), 40)) / 3;
            int editHeight = mBinding.feedbackContentEdit.getHeight();
            editHeight = editHeight == 0 ? AnkoDimensionsKt.dp2px(getContext(), 130) : mBinding.feedbackContentEdit.getHeight();
            int layoutMargin = AnkoDimensionsKt.dp2px(getContext(), 20);//距离上部应用的间隔
            int marginTop = itemHeight * row + editHeight + layoutMargin;//+ itemSpace * (row - 1)
            RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) mBinding.bottomLl.getLayoutParams();
    
            //用户判断 在每次fix底部布局高度后用来判断底部按钮的点击位置 注意要减去顶部edittext的高度
            judgeClickMargin = marginTop - editHeight;
    
            params.setMargins(0, marginTop, 0, 0);
            mBinding.bottomLl.setLayoutParams(params);
        }

    记得在页面初始化和对应item发生变化的方法里要调用此方法进行布局设置。

    6:底部位置的点击(这点可以不考虑)

    由于设置RecyclerView是高度设置是android:layout_height="wrap_content",这样RecyclerView就不会拦截底部布局的点击事件,所以点击操作只需要用id在代码中进行点击事件的判断即可,就不需要下面的这些操作了

    由于RecyclerView是高度设置是android:layout_height="match_parent",在整个界面的内容没有超过屏幕时,点击布局其实监听进入的是RecyclerView的OnItemTouchListener监听,所以要进行两层点击判断

    • 继承RecyclerView.OnItemTouchListener对里面的方法进行处理
    import android.view.GestureDetector;
    import android.view.MotionEvent;
    import android.view.View;
    
    import androidx.annotation.NonNull;
    import androidx.core.view.GestureDetectorCompat;
    import androidx.recyclerview.widget.RecyclerView;
    
    /**
     * RecyclerViewde 的点击  进行拖拽的布局会照成recyclerview下方的布局无法点击,需要在RecyclerView点击里重新设置
     * <p>
     * 因为我们自带的适配器已近设置了item的点击和长按点击的功能,这边就把这2个点击屏蔽
     *
     * @author Wuczh
     * @date 2021/12/1
     */
    public abstract class OnRecyclerItemClickListener implements RecyclerView.OnItemTouchListener {
        private GestureDetectorCompat mGestureDetectorCompat;
        private RecyclerView mRecyclerView;
    
        public OnRecyclerItemClickListener(RecyclerView recyclerView) {
            mRecyclerView = recyclerView;
            mGestureDetectorCompat = new GestureDetectorCompat(mRecyclerView.getContext(),
                    new ItemTouchHelperGestureListener());
        }
    
        @Override
        public boolean onInterceptTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e) {
            mGestureDetectorCompat.onTouchEvent(e);
            return false;
        }
    
        @Override
        public void onTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e) {
            mGestureDetectorCompat.onTouchEvent(e);
        }
    
        @Override
        public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
    
        }
    
        //    public abstract void onItemClick(RecyclerView.ViewHolder viewHolder);
        //
        //    public abstract void onLongClick(RecyclerView.ViewHolder viewHolder);
    
        public abstract void onOtherClick(MotionEvent e);
    
        private class ItemTouchHelperGestureListener extends GestureDetector.SimpleOnGestureListener {
            @Override
            public boolean onSingleTapUp(MotionEvent e) {
                View childViewUnder = mRecyclerView.findChildViewUnder(e.getX(), e.getY());
                if (childViewUnder != null) {
                    RecyclerView.ViewHolder childViewHolder = mRecyclerView.getChildViewHolder(childViewUnder);
                    //                onItemClick(childViewHolder);
                } else {
                    onOtherClick(e);
                }
                return true;
            }
    
            @Override
            public void onLongPress(MotionEvent e) {
                View childViewUnder = mRecyclerView.findChildViewUnder(e.getX(), e.getY());
                if (childViewUnder != null) {
                    RecyclerView.ViewHolder childViewHolder = mRecyclerView.getChildViewHolder(childViewUnder);
                    //                onLongClick(childViewHolder);
                }
            }
    
        }
    }

    在回调进行布局位置判断,设置对应点击

            mBinding.picRv.addOnItemTouchListener(new OnRecyclerItemClickListener(mBinding.picRv) {
                @Override
                public void onOtherClick(MotionEvent e) {
                        int bottomItemHeight = AnkoDimensionsKt.dp2px(getContext(), 50);//历史意见反馈的高度
                    if (e.getY()>judgeClickMargin) {
                        int between=(int)e.getY()-judgeClickMargin;//判读触摸点与 bottom布局分界处的距离
                        int oneItem=(bottomItemHeight);//一个textview+一个分割线的高度
                        if (between>0 && between<=oneItem) {
                            //点击在第一个textview上 ---所在位置
                            FeedBackHistoryActivity.start(getContext());
                        }
    //                    else if (between>oneItem && between<=2*oneItem) {
    //
    //                        //点击在第二个textview上 ---谁可以看
    //                        ToastUtil.normal("谁可以看");
    //                    } else if (between>2*oneItem && between<=3*oneItem) {
    //
    //                        //点击在第三个textview上 ---提醒谁看
    //                        ToastUtil.normal("提醒谁看");
    //                    } else if (between>3*oneItem && between<=4*oneItem && e.getX()>=leftMargin && e.getX()<=(starWidth+leftMargin)) {
    //                        //点击星星 同步到空间
    //                        ToastUtil.normal("同步到空间");
    //                    }
    
                    }
                }
            });
    • 当界面超过屏幕时,采用布局的id设置点击事件
      //意见反馈
            mBinding.feedbackHistoryTv.setOnClickListener(v -> FeedBackHistoryActivity.start(getContext()));

    以上就是拖拽删除的主要操作

    附上demo的guthub下载路径:GitHub - WCaiZhu/PictureDrag: 仿微信进行拍照、选择图片后进行图片拖拽删除

    展开全文
  • 效果图: 一、在app的build中引入相应的框架 //recyclerview implementation "androidx.recyclerview:recyclerview:1.1.0" //glide implementation ...//导入相册多图片选择库 implementation .

    效果图:

     一、在app的build中引入相应的框架

    //recyclerview
    implementation "androidx.recyclerview:recyclerview:1.1.0"
    //glide
    implementation "com.github.bumptech.glide:glide:4.10.0"
    implementation "com.github.bumptech.glide:compiler:4.10.0"
    //导入相册多图片选择库
    implementation 'com.github.donkingliang:ImageSelector:2.1.1'
    //压缩文件,压缩图片,压缩Bitmap
    implementation 'com.github.nanchen2251:CompressHelper:1.0.5'

    2. 对图片进行压缩处理 ImageCompressUtil

    package com.ruidde.csndresourcedemo.unilt;
    
    import android.graphics.Bitmap;
    import android.graphics.BitmapFactory;
    
    import java.io.BufferedInputStream;
    import java.io.ByteArrayOutputStream;
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.IOException;
    import java.io.InputStream;
    import java.net.HttpURLConnection;
    import java.net.URL;
    
    /**
     * 对图片进行压缩处理
     */
    public class ImageCompressUtil {
        /**
         * 通过压缩图片的尺寸来压缩图片大小,仅仅做了缩小,如果图片本身小于目标大小,不做放大操作
         *
         * @param pathName     图片的完整路径
         * @param targetWidth  缩放的目标宽度
         * @param targetHeight 缩放的目标高度
         * @return 缩放后的图片
         */
        public static Bitmap compressBySize(String pathName, int targetWidth, int targetHeight) {
            BitmapFactory.Options opts = new BitmapFactory.Options();
            opts.inJustDecodeBounds = true;
            // 不去真的解析图片,只是获取图片的头部信息,包含宽高等;
            Bitmap bitmap = BitmapFactory.decodeFile(pathName, opts);
            // 得到图片的宽度、高度;
            int imgWidth = opts.outWidth;
            int imgHeight = opts.outHeight;
            // 分别计算图片宽度、高度与目标宽度、高度的比例;取大于等于该比例的最小整数;
            int widthRatio = (int) Math.ceil(imgWidth / (float) targetWidth);
            int heightRatio = (int) Math.ceil(imgHeight / (float) targetHeight);
            if (widthRatio > 1 || heightRatio > 1) {
                if (widthRatio > heightRatio) {
                    opts.inSampleSize = widthRatio;
                } else {
                    opts.inSampleSize = heightRatio;
                }
            }
            // 设置好缩放比例后,加载图片进内容;
            opts.inJustDecodeBounds = false;
            opts.inPreferredConfig = Bitmap.Config.RGB_565;
            opts.inDither = true;
    
            bitmap = BitmapFactory.decodeFile(pathName, opts);
            return bitmap;
        }
    
    }
    

    3.选中图片的Adapter:PhotoImagsAdapter

    package com.ruidde.csndresourcedemo;
    
    import android.content.Context;
    import android.graphics.Bitmap;
    import android.os.Environment;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.ImageView;
    import android.widget.RelativeLayout;
    
    import androidx.annotation.NonNull;
    import androidx.recyclerview.widget.RecyclerView;
    
    import com.bumptech.glide.Glide;
    import com.nanchen.compresshelper.CompressHelper;
    
    import java.io.File;
    import java.util.ArrayList;
    import java.util.List;
    
    class PhotoImagsAdapter extends RecyclerView.Adapter<PhotoImagsAdapter.InfoImageHolder> {
    
        private Context context;
        private List<String> mDatas = new ArrayList<>();
    
        public PhotoImagsAdapter(Context context, List<String> mDatas) {
            this.context = context;
            this.mDatas = mDatas;
        }
    
        public void setmDatas(List<String> mDatas) {
            this.mDatas = mDatas;
            notifyDataSetChanged();
        }
    
        @NonNull
        @Override
        public PhotoImagsAdapter.InfoImageHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
            View v = LayoutInflater.from(context).inflate(R.layout.item_info_img, parent, false);
            return new InfoImageHolder(v);
        }
    
        @Override
        public void onBindViewHolder(@NonNull InfoImageHolder holder, final int position) {
            /**
             * 数据操作
             */
            if (mDatas != null && mDatas.size() > 0) {
                if (mDatas.size() == position) {
                    holder.img_photo.setImageResource(R.mipmap.img_add);
                    holder.btn_clearResource.setVisibility(View.GONE);
                } else {
                    String dateStr = mDatas.get(position);
                    holder.btn_clearResource.setVisibility(View.VISIBLE);
                    /**
                     * 在Activity里面使用
                     * dateStr 图片的绝对路径
                     * */
                    File oldFile = new File(dateStr);
    //                File newFile = CompressHelper.getDefault(this).compressToFile(oldFile);
    //                File newFile = new CompressHelper.Builder(context)
    //                        .setMaxWidth(360)  // 默认最大宽度为720
    //                        .setMaxHeight(480) // 默认最大高度为960
    //                        .setQuality(80)    // 默认压缩质量为80
    //                        .setCompressFormat(Bitmap.CompressFormat.JPEG) // 设置默认压缩为jpg格式
    //                        .setDestinationDirectoryPath(Environment.getExternalStoragePublicDirectory("Aruidde").getAbsolutePath()) //压缩图片所在路径
    //                        .build()
    //                        .compressToFile(oldFile);
                    /**
                     * 但是不会存储压缩后的图片
                     * 压缩后的Bitmap
                     * */
    //                Bitmap bitmap = CompressHelper.getDefault(context).compressToBitmap(oldFile);
                    Bitmap bitmap = new CompressHelper.Builder(context)
                            .setMaxWidth(360)  // 默认最大宽度为720
                            .setMaxHeight(480) // 默认最大高度为960
                            .build()
                            .compressToBitmap(oldFile);
    
                    /**
                     * 适合API 28
                     * 将图片压缩并转化为Bitmap
                     * */
    //                Bitmap arrBitmap = ImageCompressUtil.compressBySize(dateStr, 300, 300);
    //                Glide.with(context).load(newFile).into(holder.img_photo);
                    Glide.with(context).load(bitmap).into(holder.img_photo);
                }
            } else {
                holder.img_photo.setImageResource(R.mipmap.img_add);
                holder.btn_clearResource.setVisibility(View.GONE);
            }
    
    
            //添加图片
            holder.img_photo.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    itemOnClickListener.onAddItenClick(position);
                }
            });
            //删除图片
            holder.btn_clearResource.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    itemOnClickListener.onDeleteItenClick(position);
                }
            });
        }
    
        @Override
        public int getItemCount() {
            return mDatas != null ? (mDatas.size() + 1) : 1;
        }
    
        /**
         * 创建ViewHolder
         * 元素声明
         */
        class InfoImageHolder extends RecyclerView.ViewHolder {
    
            ImageView img_photo;
            ImageView btn_clearResource;
            RelativeLayout re_imgResourxe;
    
            public InfoImageHolder(@NonNull View itemView) {
                super(itemView);
                img_photo = itemView.findViewById(R.id.img_photo);
                btn_clearResource = itemView.findViewById(R.id.btn_clearResource);
                re_imgResourxe = itemView.findViewById(R.id.re_imgResourxe);
            }
        }
    
        //添加图片
        private InfoImgClickListener itemOnClickListener;
    
        interface InfoImgClickListener {
            void onAddItenClick(int addPosition);
    
            void onDeleteItenClick(int deletePosition);
        }
    
        public void setAddImgClickLisitenner(InfoImgClickListener itemOnClickListener) {
            this.itemOnClickListener = itemOnClickListener;
        }
    }
    

    4.布局xml

    (1)。item_info_img

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">
    
        <RelativeLayout
            android:id="@+id/re_imgResourxe"
            android:layout_centerVertical="true"
            android:visibility="visible"
            android:layout_width="235px"
            android:layout_height="235px">
    
            <ImageView
                android:id="@+id/img_photo"
                android:layout_width="200px"
                android:layout_height="200px"
                android:layout_centerInParent="true"
                android:scaleType="fitXY"
                android:src="@mipmap/img_add"/>
    
            <ImageView
                android:id="@+id/btn_clearResource"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:src="@mipmap/img_exit"
                android:padding="10px"
                android:layout_marginTop="-10px"
                android:layout_marginRight="-10px"
                android:layout_alignParentRight="true"/>
    
        </RelativeLayout>
    
    </RelativeLayout>
    

    (2)。主Activity布局

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/img_recycleview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_margin="10dp"
        app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
        app:spanCount="4"
        tools:listitem="@layout/item_info_img"/>

    5.最主要通过 FileProvider 创建共享文件

    在res文件夹下创建xml文件并创建 file_paths.xml文件

    <?xml version="1.0" encoding="utf-8"?>
    <paths>
        <paths>
            <external-path name="images" path="Pictures" />
            <external-path path="jzFile" name="image" />
            <external-files-path name="jzApp.apk" path="Download"/>
        </paths>
    </paths>

    Mainfest文件中添加注册

    <provider
        android:name="androidx.core.content.FileProvider"
        android:authorities="com.ruidde.csndresourcedemo.fileProvider"
        android:exported="false"
        android:grantUriPermissions="true">
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/file_paths" />
    </provider>

    具体Demo

    展开全文
  • 百度网盘图片无法删除

    千次阅读 2020-05-25 17:50:21
    百度网盘客户端图片选项里面是没有图片的,但是无法注销百度帐号,后来找到百度网盘网页版图片选项里面有一些灰白色的图片并且无法删除,我尝试过重新登录,清除网站数据,更换浏览器,结果百度网盘网页版还是有那些...

    百度网盘图片无法删除

    百度网盘客户端图片选项里面是没有图片的,但是无法注销百度帐号,后来找到百度网盘网页版图片选项里面有一些灰白色的图片并且无法删除,我尝试过重新登录,清除网站数据,更换浏览器,结果百度网盘网页版还是有那些图片并且无法删除,我也问题反馈过,但是感觉没用,哪位大佬知道该怎么办吗?

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    展开全文
  • 小程序图片上传及预览和删除

    千次阅读 2019-04-12 16:13:30
    其中wx:for="{{picArr}}"为所有的图片张数,src为img 的图片路径 ; 自定义data-src为当前点击的图片路劲(为预览做准备)自定义data-list为所有的图片张数(为预览做准备) <block wx:key="imgbox" wx:for="{{...
  • 利用微信的weui框架上传、预览和删除图片

    万次阅读 热门讨论 2018-03-09 09:48:31
    jQuery WeUI 是专为微信公众账号开发而设计的一个框架,jQuery WeUI的官网:http://jqweui.com/需求:需要在微信公众号网页添加上传图片功能技术选型:实现上传图片功能可选百度的WebUploader、饿了么的Element和...
  • 项目中需要上传图片处理,项目框架使用的是Springmvc,其中查阅资料springmvc已经封装了MultipartFile类,其中的transferTo方法上传图片文件时,无法进行删除图片文件,故记录下解决问题途径 上传代码截图: ...
  • Android GridView扩展仿微信微博发图动态添加删除图片

    万次阅读 热门讨论 2016-11-04 14:29:35
    在平时的开发中,我们会看到不管是微信发朋友圈照片还是微博发布新鲜事,添加图片的时候都是选完后面还有个+号再去选择图片,这样的话比较方便用户去添加图片,有的右上角还有个...添加图片的+号图片 删除图片的图片
  • html部分   &lt;span class="delete" @click="showFiguredelete(index)"&gt;×&lt;/span&gt; js部分 showFiguredelete(index){  var that=this;... console.l...
  • 一、小红书效果 上面三个图是小红书发布动态的时候选择好图片后,长按图片进行排序的效果。长按后,选择的图片浮起,随手指左右移动,靠近左右边缘的...2.当图片满足9个的时候将最后位置的+隐藏,小于9...
  • 要求是不使用图片,实现右上角删除键功能 实现流程: a. 使用输入法工具(比如搜狗输入法工具箱,也可以使用电脑自带的“字符映射表”)找到符号“ × ”; b. 在一个div块级元素中放置符号“ × ”,使用strong...
  • &lt;div class="item"...上传项目图片&lt;/div&gt; &lt;div class="contain_upload"&gt; &lt;div class="tip"&gt;包括但不限于:项目效果
  • 这里更改图片默认编号Figure 2:为Fig 1.: ** 提示: #程序如下: \begin{figure}[htbp]  \begin{center}   \subfigure[Positions trajectories and errors]{  \includegraphics[width=0.47\...
  • 删除microsoftIf you only pay attention to the headlines that Microsoft wants you to keep your eye on, you’d be forgiven for thinking that Windows 10 has been a universal success. So far, Redmond’s ...
  • 如果当前流程引擎中已存在相同key的流程,则找到当前key对应的最高版本,在最高版本上加1 */ public void queryProcessDefinition() throws Exception { // 获取仓库服务对象 RepositoryService ...
  • 文章目录删除上传到服务器的临时文件前言说明正文目的背景代码第一种实现方式第二种实现方式测试结果 删除上传到服务器的临时文件 前言 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&...
  • 新浪微博本身不提供批量删除微博的方法,而有些时候,我们需要删除自己微博上所有带图片的内容,比如最近富二代王思聪就清空了自己的微博。 下面就是一个批量删除微博的方法,包括带图片微博的方法。 先使用谷歌...
  • .com.pingan.paces.ccms 平安口袋银行(旧版目录,可删除) 新版本目录已移至Andriod的data目录下,所以可以放心删除。 PASpeechSDK 平安的某个SDK(可删除) 目前没有发现用处,该目录为空,可删除
  • 今天分享一下从搭建web服务器,到向服务器发送图片,以及加载图片的整体实现。 因为是Demo演示,所以尽可能的简单、详细且实用,有什么错误敬请指正。 先看一下效果图: 文章参考:Unity向Web服务器上传和下载图片 ...
  • WPS删除多余插件

    千次阅读 2021-07-29 11:34:45
    以macOS 为例 ...5.选择不用的插件,例如【云文档】(对应的是【kclouddocs】文件夹),进行删除 6.像在wps 经常出现的在线字体,在这里就可以直接移除掉 移除前 移除后,清爽很多 ...
  • 新手或者老手,有没有手欠的revoke过Member Center中的各种证书,删除过各种mobileprovision文件?一、个人证书、公司证书和企业证书的区别苹果对开发者主要分为3类:个人、组织(公司、企业)、教育机构。即: 1、...
  • 这个思路是隐藏 el-upload–picture-card” ...这样在上传中那个"+"也可以马上隐藏 上传组件代码块 <el-form-item label="产品图片:" size="mini"> <el-upload action="上传接口" :limit="1" :on-pr...
  • layui实现单个删除和批量删除

    千次阅读 2019-12-05 16:32:17
    文章目录layui实现单个删除和批量删除先获得表格数据一、单个删除1、在js文件中绑定操作工具栏的删除操作2、domain层:3、controller层:4、service层:5、dao层:二、批量删除1、首先在页面上定义批量删除按钮2、在...
  • 图片验证码是验证码的一种,图片验证码常见的形式有输入图片中字母、数字等,目前的发展更为多元。下面小编从多方面跟大家讲讲图片验证码。 ➤验证码的前世今生 全自动区分计算机和人类的图灵测试(Completely ...
  • Java实现阿里OSS上传和删除

    千次阅读 2019-01-13 09:26:57
    依赖 &lt;!-- httpclient --&gt; &lt;dependency&gt; &lt;groupId&gt;org.apache.httpcomponents&lt;/groupId&gt; &lt;artifactId&gt;httpclient&.../version&
  • 在工作中,经常需要将一个商品表格插入商品的图片,比如在鞋服箱包等行业,那是经常要用到Excel中的商品需要插入商品的图片,如果一个个的插入,那会疯掉的,所以根据自己所在的鞋业行业,和借鉴了前辈的部分代码,...
  • 您可以永久删除您的帐户,删除所有推文,关注者,收藏夹和其他数据。 它几乎会立即从Twitter消失,并将在30天之内从Twitter的服务器上完全擦除。 停用方式 (How Deactivation Works) Visit the Twitter website in ...
  • 群主和发送信息者可以删除漫游的聊天记录,删除后,其他群成员将不能看到被删除的聊天内容。 二、群空间论坛或是群相册有不良信息: 可联系群主或群管理员可以对论坛或相册进行删除操作。若群主或管理员不愿意操作...
  • 最近在开发IM软件,需要做:长按弹出菜单,删除,分享,更多,撤回. 先看看效果是不是你想要的 使用处的代码 _menuView() { bool isCanRecall = DateTime.now().millisecondsSinceEpoch - dateTime....
  • mui图片上传

    千次阅读 热门讨论 2019-05-11 14:26:12
    作为一个后台开发人员、写这个真的是浪费不少脑细胞,虽然做出来了,但是也很麻烦,如果哪位大哥或者小妹妹那里有简单点的,我跪求!...点击那个加号(注:这个 + (加号)是图标不是图片,不会弄的找前端的给弄)会...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 203,663
精华内容 81,465
关键字:

删除号图片