精华内容
下载资源
问答
  • Android中仿QQ侧滑删除功能的实现

    千次阅读 2018-04-19 16:55:40
    背景 参考 ...我体验了好多的app,感觉删除功能还是QQ的侧滑删除最适合我的习惯。查找了github上的开源优秀项目,了一个使用起来比较简单的框架,下面来实现。 参考 Android 仿QQ侧滑...

    背景

    侧滑删除的功能和效果很棒,而且用户体验感会很好,更加效率点吧!我体验了好多的app,感觉删除的功能还是QQ的侧滑删除最适合我的习惯。查找了github上的开源优秀项目,找了一个使用起来比较简单的框架,下面来实现。


    参考

    Android 仿QQ侧滑删除—一个满足ListView、RecyclerView以及其他View通用的侧滑删除

    该链接可以让你熟悉自定义VIewGroup的一些基本步骤,然后大体的讲了一些侧滑菜单实现基本原理,个人觉得是可以让人学到知识点的好文

    SwipeDelMenuLayout

    该链接就是我使用的框架,点开可以阅读该框架的一些基本使用方法。当然,有时间可以去好好的研究一下源码,肯定可以学习很多的好东西。


    框架引入

    想要使用这个框架我们需要在项目中引用框架。

    • 在项目根build.gradle文件中增加JitPack仓库依赖
    allprojects {
            repositories {
                ...
                maven { url "https://jitpack.io" }
            }
        }
    • 添加依赖
    dependencies {
        ...
        implementation 'com.github.mcxtzhang:SwipeDelMenuLayout:V1.3.0'
    }

    这里说明一下添加依赖时为什么不是compile,因为我刚刚更新了一下studio,然后添加依赖的时候它建议我使用implementation 来代替compile。如果你的不是高版本的studio,那么可以继续使用compile。

    • 在需要侧滑删除的ContentItem外面套上本控件,在本控件内依次排列ContentItem、菜单即可

    我的Demo说明

    这里我就简单的使用listview来展现数据,并实现侧滑菜单的功能。因为方法都是通用的,所以大家根据需求自己去具体实现即可。阅读上面我参考的框架使用文档,上面有讲很多应用场景,基本适用于大多数的ViewGroup。


    主界面布局和代码

    就是简单的一个listview控件,然后呈现数据即可。

    package com.example.administrator.sideslipdeletedemo;
    
    import android.app.Activity;
    import android.os.Bundle;
    import android.widget.ListView;
    
    import java.util.ArrayList;
    import java.util.List;
    
    public class MainActivity extends Activity {
    
        private ListView lsv_side_slip_delete;
        private List<String> list = new ArrayList<>();
        private SideSlipAdapter adapter;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            setViews();// 控件初始化
            setData();// 初始化模拟数据
            setAdapter();// 创建adapter,listview设置adapter
            setListeners();// 设置监听
        }
    
        /**
         * 设置监听
         */
        private void setListeners() {
            if (adapter != null){
                // 注册监听器,回调用来刷新数据显示
                adapter.setDelItemListener(new SideSlipAdapter.DeleteItem() {
                    @Override
                    public void delete(int pos) {
                        list.remove(pos);
                        adapter.notifyDataSetChanged();
                    }
                });
            }
        }
    
        /**
         * 创建adapter并且listview设置adapter
         */
        private void setAdapter() {
            adapter = new SideSlipAdapter(this, list);
            lsv_side_slip_delete.setAdapter(adapter);
    
        }
    
        /**
         * 模拟初始化数据
         */
        private void setData() {
            for (int i = 0;i < 16;i++){
                list.add("侧滑删除" + (i + 1));
            }
        }
    
        /**
         * 控件初始化
         */
        private void setViews() {
            lsv_side_slip_delete = findViewById(R.id.lsv_side_slip_delete);
        }
    }
    
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout 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:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">
    
        <ListView
            android:id="@+id/lsv_side_slip_delete"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"/>
    
    </LinearLayout>

    适配器代码以及itemView的布局

    package com.example.administrator.sideslipdeletedemo;
    
    import android.content.Context;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.BaseAdapter;
    import android.widget.Button;
    import android.widget.TextView;
    import android.widget.Toast;
    
    import com.mcxtzhang.swipemenulib.SwipeMenuLayout;
    
    import java.util.List;
    
    public class SideSlipAdapter extends BaseAdapter{
    
        private LayoutInflater inflater;
        private List<String> list;
        private Context context;
    
        public SideSlipAdapter(Context context, List<String> list) {
            this.inflater = LayoutInflater.from(context);
            this.list = list;
            this.context = context;
        }
    
        @Override
        public int getCount() {
            return list.size();
        }
    
        @Override
        public Object getItem(int position) {
            return list.get(position);
        }
    
        @Override
        public long getItemId(int position) {
            return position;
        }
    
        @Override
        public View getView(final int position, View convertView, ViewGroup parent) {
            ViewHolder holder = null;
            View closeView = null;
            if (convertView == null){
                convertView = inflater.inflate(R.layout.listview_item_delete, parent, false);
                holder = new ViewHolder();
                holder.tv_delete = convertView.findViewById(R.id.content);
                holder.btn_top = convertView.findViewById(R.id.btnTop);
                holder.btn_delete = convertView.findViewById(R.id.btnDelete);
                convertView.setTag(holder);
            }
    
            if (closeView == null){
                closeView = convertView;
            }
            final View finalCloseView = closeView;// listView的itemView
    
            holder = (ViewHolder) convertView.getTag();
            holder.tv_delete.setText(list.get(position));
    
            // 置顶按钮的单击事件
            holder.btn_top.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Toast.makeText(context, "置顶", Toast.LENGTH_SHORT).show();
                    ((SwipeMenuLayout)(finalCloseView)).quickClose();// 关闭侧滑菜单:需要将itemView强转,然后调用quickClose()方法
                }
            });
    
            // 删除按钮的单击事件
            holder.btn_delete.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    ((SwipeMenuLayout)(finalCloseView)).quickClose();// 关闭侧滑菜单
                    if (delItemListener != null){
                        delItemListener.delete(position);// 调用接口的方法,回调删除该项数据
                    }
                }
            });
    
            return convertView;
        }
    
        /**
         * 缓存控件用
         */
        static class ViewHolder{
            TextView tv_delete;// 展示内容
            Button btn_top;// 置顶
            Button btn_delete;// 删除
        }
    
        // 定义接口,包含了删除数据的方法
        interface DeleteItem{
            void delete(int pos);
        }
    
        private DeleteItem delItemListener;
        // 设置监听器的方法
        public void setDelItemListener(DeleteItem delItemListener){
            this.delItemListener = delItemListener;
        }
    }
    
    <?xml version="1.0" encoding="utf-8"?>
    <com.mcxtzhang.swipemenulib.SwipeMenuLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:clickable="true"
        app:swipeEnable="true"
        app:leftSwipe="true"
        app:ios="true">
    
        <!-- itemView的内容,这里我简单的使用了一个textview。
        如果是更加复杂的布局,大家可以在外面包裹一个父布局,如LineatLayout,
        然后在这个父布局里面设置你想要展示的复杂内容。listview的每一个item展示的
        内容就是这个布局确定的,必须要有。-->
        <TextView
            android:id="@+id/content"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="?android:attr/selectableItemBackground"
            android:gravity="center"
            android:text="项目中我是任意复杂的原ContentItem布局"/>
    
        <!-- 侧滑菜单选项,这里可以有多个选项。我这里就用了置顶和删除两个选项-->
        <Button
            android:id="@+id/btnTop"
            android:layout_width="60dp"
            android:layout_height="match_parent"
            android:background="@android:color/darker_gray"
            android:text="置顶"
            android:textColor="@android:color/white"/>
    
        <Button
            android:id="@+id/btnDelete"
            android:layout_width="60dp"
            android:background="@android:color/holo_red_dark"
            android:layout_height="match_parent"
            android:text="删除"
            android:textColor="@android:color/white"/>
    
    </com.mcxtzhang.swipemenulib.SwipeMenuLayout>
    

    效果图示

    这里写图片描述


    关键说明

    我上面给出的代码和布局中,关键的就是listView的itemView的布局,这个布局我使用的根布局就是框架中的布局:SwipeMenuLayout。

    需要设置一些必要的属性。

        android:clickable="true"// 必要
        app:swipeEnable="true"// 设置true
        app:leftSwipe="true"// ture表示支持左滑,false表示支持右滑
        app:ios="true"// 是否是IOS阻塞式交互

    根布局设置的时候,上面就用如上设置即可。

    我还在itemView的布局中添加了一些注释说明,itemView需要包含哪些内容。

    若是在ListView、RecyclerView中使用,点击事件正确的设置应该是在 Adapter 里对 ContentItem 设置,不能使用listview.setOnItemClickListener。 因为此时 Item 是本控件了,不是里面的 ContentItem 那块区域了,且本控件区域有很多触摸的判断,内部包含 ContentItem 和侧滑菜单 Menu。


    A little bit of progress every day!Come on!

    展开全文
  • 如何在Word2013中删除图片的背景

    千次阅读 2017-11-17 09:49:26
    1、用Word2013打开一篇文档,选择我们需要删除背景的图片,此时文档会自动切换“图片工具->格式”选项卡,我们单击“调整”组中的“删除背景”按钮。 2、此时文档会自动切换“图片工具->
    如果你只是不想要你插入到文档中的图片的某一小部分,试问你应该怎么办呢?其实很简单,你可以删除图片的背景哦!在Word2013中是可以这么做的,不信的话你就来试试吧。

    操作步骤如下:

    1、用Word2013打开一篇文档,选择我们需要删除背景的图片,此时文档会自动切换到“图片工具->格式”选项卡,我们单击“调整”组中的“删除背景”按钮。

    选择删除背景按钮

    2、此时文档会自动切换到“图片工具->背景消除”选项卡,并且图片内出现了可见的白色控点,我们用鼠标拖放的方式调整所选的区域,注意所选区域是要保留背景的。

    选择保留图片背景的区域

    3、选好我们保留背景的图片区域后,单击“关闭”组中的“保留更改”按钮。

    单击保留更改按钮

    4、我们图片的背景已经删除完成了,效果如下:

    删除图片背景的效果

    注意:我们这里所说的删除图片的背景与图片处理软件中裁剪工具的功能是不同的,它并没有修改图片的大小。

    http://www.topdf.cn/htmltopdf
    展开全文
  • 在打开visio文件或者想要在控制面板中卸载Visio软件时,均提示“Windows找不到文件,请确定文件名是否正确后,再试一次”。 并且想重新安装Visio时,点击安装文件“setup.exe”,电脑无反应。 2 解决 2...

    Visio,找不到文件,请确定文件名是否正确后,再试一次

    1 背景

    此前在卸载office时不懂事,乱删了一些注册值等信息,导致后来尽管成功装上了office2016并激活,但是安装的VisioPro2013却出了问题,无法使用。
    在打开visio文件或者想要在控制面板中卸载Visio软件时,均提示“Windows找不到文件,请确定文件名是否正确后,再试一次”。
    在这里插入图片描述
    并且想重新安装Visio时,点击安装文件“setup.exe”,电脑无反应。

    2 解决

    2.1 清除残留注册表

    在腾讯电脑管家的主页面可以看见一个“清理垃圾”选项,打开此功能;腾讯电脑管家会有默认清理项,可以根据自己的需求进行选项改动,打开“查看详情”,进行选择,见下图;如果清理错误,还可以使用“还原注册表”功能,对注册表进行还原。详情可参考link
    在这里插入图片描述
    通过此步骤,可以将卸载后的Visio残余注册表删除干净。此时可以看到控制面板“应用”中不再有“Visio”这个软件存在。

    2.2 重新安装VisioPro2013

    VisioPro2013 百度云链接link,提取码:rosn。
    安装完成后,重启电脑,但是当打开visio文件时,报如下错误“Microsoft Office无法验证此产品的许可证,应使用控制面板修复Office程序”。
    在这里插入图片描述
    此时分三步进行尝试。
    第一步。应用激活软件,尝试激活电脑中的Office2013,激活软件 百度云链接link,提取码:ey0g。
    第二步。若第一步不成功,则进行第二步,通过修改“服务”窗口或注册表解决,详情可见link
    第三步。若第二步仍旧不成功,则进行第三步,则检查自己的Visio或Office软件是否安装在C盘,若没有,则卸载重新安装。

    3 总结

    遇到电脑相关的问题时,只能通过不断尝试各种方式以求解决。

    【整理不易,转载请注明出处和相关链接,否则必究!】

    展开全文
  • 这个项目使用了RecyclerView的ItemTouchHelper类实现了Item的拖动和删除功能,ItemTouchHelper是v7包下的一个类,我们看一下他的介绍 This is a utility class to add swipe to dismiss and drag &

    先上效果图:
    这里写图片描述

    本篇文章我们来学习一个开源项目Android-ItemTouchHelper-Demo
    这个项目使用了RecyclerView的ItemTouchHelper类实现了Item的拖动和删除功能,ItemTouchHelper是v7包下的一个类,我们看一下他的介绍

    This is a utility class to add swipe to dismiss and drag & drop support to RecyclerView.

    这是一个工具类,专门用来配合RecyclerView实现滑动删除和拖拽功能的类

    先搭起一个小框架

    我们从头开始,一点一点实现最终的功能,首先我们先搭起一个小框架,我们的首页显示两个Item,一个点击进入ListView形式的RecyclerView;一个点击进入GridView形式的RecyclerView。
    这里写图片描述

    我们先在values/strings.xml中定义一个数组

     <array name="main_items">
            <item>List - Basic Drag and Swipe</item>
            <item>Grid - Basic Drag</item>
     </array>

    再创建一个MainFragment继承自ListFragment

    public class MainFragment extends ListFragment {
        private onListItemClickListener mListItemClickListener;
        //定义一个回调接口,用来将点击事件传回他的宿主Activity去做,Fragment中不做具体的逻辑操作
        public interface onListItemClickListener{
            void onListItemClick(int position);
        }
        public MainFragment(){
    
        }
    
        @Override
        public void onAttach(Context context) {
            super.onAttach(context);
            //他的宿主Activity将实现onListItemClickListener接口
            //使用getActivity()获得的宿主Activity,将他强转成onListItemClickListener接口
           mListItemClickListener = (onListItemClickListener)getActivity();
        }
    
        @Override
        public void onActivityCreated(Bundle savedInstanceState) {
            super.onActivityCreated(savedInstanceState);
            //获得我们在strings.xml中定义个数组
            final String[] items = getResources().getStringArray(R.array.main_items);
            //创建适配器
            final ArrayAdapter<String> adapter = new ArrayAdapter<>(getActivity(),
                    android.R.layout.simple_list_item_1, items);
            //设置适配器
            setListAdapter(adapter);
        }
    
        @Override
        public void onListItemClick(ListView l, View v, int position, long id) {
            if (mListItemClickListener!=null){
                //由于宿主Activity实现了onListItemClickListener接口
                //因此调用的是宿主Activity的onListItemClick方法
                //并且将点击的item的position传给Activity
                mListItemClickListener.onListItemClick(position);
            }
        }
    }

    我们再创建一个RecyclerListFragment,我们先不做具体的实现,只是先把架子搭起来

    public class RecyclerListFragment extends Fragment {
        public RecyclerListFragment(){}
    
        @Nullable
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
            return new RecyclerView(container.getContext());
        }
    }

    再来一个RecyclerGridFragment

    public class RecyclerGridFragment extends Fragment {
        public RecyclerGridFragment(){}
    
        @Nullable
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
            return new RecyclerView(container.getContext());
        }
    }

    好了,Fragment我们已经准备好了,就差一个宿主Activity了,现在我们就来创建MainActivity,并且实现MainFragment.OnListItemClickListener接口,重写onListItemClick方法

    public class MainActivity extends AppCompatActivity implements MainFragment.onListItemClickListener{
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            //当savedInstanceState为null时才new一个MainFragment出来
            //否则每次旋转屏幕都会new出来一个
            if (savedInstanceState == null){
                MainFragment fragment = new MainFragment();
                //用add将MainFragment添加到framelayout上
                getSupportFragmentManager().beginTransaction()
                        .add(R.id.content,fragment)
                        .commit();
            }
        }
    
    
        @Override
        public void onListItemClick(int position) {
            //当MainFragment的Item被点击后,就会回调此方法
            //在此方法中写真正的逻辑,这样Activity和Fragment
            //之间就是松耦合关系,MainFragment可以复用
            Fragment fragment = null;
            switch (position){
                case 0:
                    //当点击第一个item时候,new一个RecyclerListFragment
                    fragment = new RecyclerListFragment();
                    break;
                case 1:
                    //当点击第二个item时候,new一个RecyclerGridFragment
                    fragment = new RecyclerGridFragment();
                    break;
            }
            //这次用replace,替换framelayout的布局,也就是MainFragment
            getSupportFragmentManager().beginTransaction()
                    .replace(R.id.content,fragment)
                    .addToBackStack(null)
                    .commit();
        }
    }

    activity_main.xml

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/main_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context=".MainActivity">
    
    
        <FrameLayout
            android:id="@+id/content"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    
    </LinearLayout>

    好了,现在我们可以运行一下,运行的结果就是一开始那个截图的效果,我们点击item会进入相应的Fragment中,但是现在是空白的,因为我们还没写完呢。

    为RecyclerView写Adapter

    我们之前使用ListView的时候,数据是靠Adapter适配到ListView上的吧,RecyclerView也是靠Adapter,所以我们先来写个Adapter吧

    public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ItemViewHolder> {
    
        /**在这里反射出我们的item的布局*/
        @Override
        public RecyclerViewAdapter.ItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            return null;
        }
        /**在这里为布局中的控件设置数据*/
        @Override
        public void onBindViewHolder(ItemViewHolder holder, int position) {
    
        }
        /**返回数据个数*/
        @Override
        public int getItemCount() {
            return 0;
        }
        /**相当于ListView中的ViewHolder*/
        public static class ItemViewHolder extends RecyclerView.ViewHolder{
    
            public ItemViewHolder(View itemView) {
                super(itemView);
            }
        }
    }

    这就是一个标准的Adapter的结构,接下来我们要逐一完善其中的方法,首先我们先在values/strings.xml中增加我们item的数组

    <array name="dummy_items">
            <item>One</item>
            <item>Two</item>
            <item>Three</item>
            <item>Four</item>
            <item>Five</item>
            <item>Six</item>
            <item>Seven</item>
            <item>Eight</item>
            <item>Nine</item>
            <item>Ten</item>
        </array>

    接着在构造方法中将数据添加到ArrayList中

     public RecyclerViewAdapter(Context context){
            //初始化数据
            mItems.addAll(Arrays.asList(context.getResources().getStringArray(R.array.dummy_items)));
        }

    然后我们再写我们item的布局文件

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        >
    
        <TextView
            android:id="@+id/text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:text="one"
            android:padding="20dp"
            android:textAppearance="?android:attr/textAppearanceMedium" />
    
        <ImageView
            android:id="@+id/handle"
            android:layout_width="?listPreferredItemHeight"
            android:layout_height="?listPreferredItemHeight"
            android:layout_alignParentRight="true"
            android:layout_centerVertical="true"
            android:scaleType="center"
            android:src="@drawable/ic_reorder_grey_500_24dp"
            />
    </RelativeLayout>

    接下来是在ItemViewHolder中进行findViewById操作

     /**相当于ListView中的ViewHolder*/
        public static class ItemViewHolder extends RecyclerView.ViewHolder{
            private TextView text;
            private ImageView handle;
            public ItemViewHolder(View itemView) {
                super(itemView);
                text = (TextView) itemView.findViewById(R.id.text);
                handle = (ImageView) itemView.findViewById(R.id.handle);
            }
        }

    然后在onCreateViewHolder中加载出布局,并且完成控件的初始化

     /**在这里反射出我们的item的布局*/
        @Override
        public RecyclerViewAdapter.ItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            //利用反射将item的布局加载出来
            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_view,null);
            //new一个我们的ViewHolder,findViewById操作都在ItemViewHolder的构造方法中进行了
            return new ItemViewHolder(view);
        }

    然后在onBindViewHolder中给控件绑定数据

     /**在这里为布局中的控件设置数据*/
        @Override
        public void onBindViewHolder(ItemViewHolder holder, int position) {
            holder.text.setText(mItems.get(position));
            //handle是我们拖动item时候要用的,目前先空着
            holder.handle.setOnTouchListener(new View.OnTouchListener() {
                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    return false;
                }
            });
        }

    还有这个方法别忘了

     /**返回数据个数*/
        @Override
        public int getItemCount() {
            return mItems.size();
        }

    好了我们一个Adapter已经写完了,然后我们来到RecyclerListFragment中给我们的RecyclerView进行配置

    public class RecyclerListFragment extends Fragment {
        public RecyclerListFragment(){}
    
        @Nullable
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
            return new RecyclerView(container.getContext());
        }
    
        @Override
        public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
            super.onViewCreated(view, savedInstanceState);
    
            RecyclerViewAdapter adapter = new RecyclerViewAdapter(getActivity());
            //参数view即为我们在onCreateView中return的view
            RecyclerView recyclerView = (RecyclerView)view;
            //固定recyclerview大小
            recyclerView.setHasFixedSize(true);
            //设置adapter
            recyclerView.setAdapter(adapter);
            //设置布局类型为LinearLayoutManager,相当于ListView的样式
            recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
    
        }
    }

    同样的,我们再来配置RecyclerGridFragment

    public class RecyclerGridFragment extends Fragment {
        public RecyclerGridFragment(){}
    
        @Nullable
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
            return new RecyclerView(container.getContext());
        }
    
        @Override
        public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
            super.onViewCreated(view, savedInstanceState);
    
            RecyclerViewAdapter adapter = new RecyclerViewAdapter(getActivity());
            RecyclerView recyclerView = (RecyclerView)view;
            recyclerView.setHasFixedSize(true);
            recyclerView.setAdapter(adapter);
            //只有这里和RecyclerListFragment不一样,这里我们指定布局为GridView样式,2列
            recyclerView.setLayoutManager(new GridLayoutManager(getActivity(),2));
    
        }
    }

    好了,现在我们可以运行了,这就是recyclerView的使用方法,接下来我们就要为recyclerView添加拖拽和侧滑删除的功能了

    实现拖拽和侧滑删除功能

    拖拽和侧滑删除的功能我们要借助ItemTouchHelper这个类,我们只需要创建出一个ItemTouchHelper对象,然后调用mItemTouchHelper.attachToRecyclerView(recyclerView);就可以了。
    我们看一下ItemTouchHelper的构造方法,他需要一个Callback

        public ItemTouchHelper(Callback callback) {
            mCallback = callback;
        }

    这个Callback是ItemTouchHelper的内部类,所以我们需要写一个类继承自ItemTouchHelper.Callback ,然后重写里面的方法

    public class SimpleItemTouchHelperCallback extends ItemTouchHelper.Callback {
        /**这个方法是用来设置我们拖动的方向以及侧滑的方向的*/
        @Override
        public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
           return 0;
        }
        /**当我们拖动item时会回调此方法*/
        @Override
        public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
    
            return false;
        }
        /**当我们侧滑item时会回调此方法*/
        @Override
        public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
    
        }
    }

    首先先来完成getMovementFlags方法

     /**这个方法是用来设置我们拖动的方向以及侧滑的方向的*/
        @Override
        public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
    
            //如果是ListView样式的RecyclerView
            if (recyclerView.getLayoutManager() instanceof LinearLayoutManager){
                //设置拖拽方向为上下
                final int dragFlags = ItemTouchHelper.UP|ItemTouchHelper.DOWN;
                //设置侧滑方向为从左到右和从右到左都可以
                final int swipeFlags = ItemTouchHelper.START|ItemTouchHelper.END;
                //将方向参数设置进去
                return makeMovementFlags(dragFlags,swipeFlags);
            }else{//如果是GridView样式的RecyclerView
                //设置拖拽方向为上下左右
                final int dragFlags = ItemTouchHelper.UP|ItemTouchHelper.DOWN|
                        ItemTouchHelper.LEFT|ItemTouchHelper.RIGHT;
                //不支持侧滑
                final int swipeFlags = 0;
                return makeMovementFlags(dragFlags,swipeFlags);
            }
        }

    当item被拖拽或者侧滑的时候会回调onMove和onSwiped方法,所以我们需要同时Adapter做出相应的改变,对mItems数据做出交换或者删除的操作,因此我们需要一个回调接口来继续回调Adapter中的方法

    public interface onMoveAndSwipedListener {
        boolean onItemMove(int fromPosition , int toPosition);
        void onItemDismiss(int position);
    }

    我们让RecyclerViewAdapter实现此接口,并且重写里面的两个方法

    public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ItemViewHolder>
                    implements onMoveAndSwipedListener

    重写两个方法

     @Override
        public boolean onItemMove(int fromPosition, int toPosition) {
            //交换mItems数据的位置
            Collections.swap(mItems,fromPosition,toPosition);
            //交换RecyclerView列表中item的位置
            notifyItemMoved(fromPosition,toPosition);
            return true;
        }
    
        @Override
        public void onItemDismiss(int position) {
            //删除mItems数据
            mItems.remove(position);
            //删除RecyclerView列表对应item
            notifyItemRemoved(position);
        }

    好了,现在我们再回到我们的SimpleItemTouchHelperCallback,在构造方法中将实现了onMoveAndSwipedListener接口的RecyclerViewAdapter 传进来

    private onMoveAndSwipedListener mAdapter;
    
        public SimpleItemTouchHelperCallback(onMoveAndSwipedListener listener){
            mAdapter = listener;
        }

    现在我们在onMove和onSwipe方法中调用mAdapter的onItemMove和onItemDismiss方法,就相当于通知adapter去做相应的改变了

     /**当我们拖动item时会回调此方法*/
        @Override
        public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
            //如果两个item不是一个类型的,我们让他不可以拖拽
            if (viewHolder.getItemViewType() != target.getItemViewType()){
                return false;
            }
            //回调adapter中的onItemMove方法
            mAdapter.onItemMove(viewHolder.getAdapterPosition(),target.getAdapterPosition());
            return true;
        }
        /**当我们侧滑item时会回调此方法*/
        @Override
        public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
            //回调adapter中的onItemDismiss方法
            mAdapter.onItemDismiss(viewHolder.getAdapterPosition());
        }

    好了,现在我们回到RecyclerListFragment中,在onViewCreated方法中添加如下几行代码,将ItemTouchHelper和recyclerView关联起来

     @Override
        public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
            super.onViewCreated(view, savedInstanceState);
    
            RecyclerViewAdapter adapter = new RecyclerViewAdapter(getActivity());
            //参数view即为我们在onCreateView中return的view
            RecyclerView recyclerView = (RecyclerView)view;
            //固定recyclerview大小
            recyclerView.setHasFixedSize(true);
            //设置adapter
            recyclerView.setAdapter(adapter);
            //设置布局类型为LinearLayoutManager,相当于ListView的样式
            recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
            //关联ItemTouchHelper和RecyclerView
            ItemTouchHelper.Callback callback = new SimpleItemTouchHelperCallback(adapter);
            mItemTouchHelper = new ItemTouchHelper(callback);
            mItemTouchHelper.attachToRecyclerView(recyclerView);
        }

    现在运行一下程序,我们已经可以实现拖拽和侧滑删除的功能了
    这里写图片描述

    现在我们为RecyclerGridFragment同样添加一下关联代码

     @Override
        public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
            super.onViewCreated(view, savedInstanceState);
    
            RecyclerViewAdapter adapter = new RecyclerViewAdapter(getActivity());
            RecyclerView recyclerView = (RecyclerView)view;
            recyclerView.setHasFixedSize(true);
            recyclerView.setAdapter(adapter);
            //只有这里和RecyclerListFragment不一样,这里我们指定布局为GridView样式,2列
            recyclerView.setLayoutManager(new GridLayoutManager(getActivity(),2));
    
            ItemTouchHelper.Callback callback = new SimpleItemTouchHelperCallback(adapter);
            mItemTouchHelper = new ItemTouchHelper(callback);
            mItemTouchHelper.attachToRecyclerView(recyclerView);
    
        }

    看一下效果
    这里写图片描述

    处理细节

    1.拖动图标即可拖拽整个item

    OK,目前我们的功能已经实现了,但是还有一些细节我们需要处理,我们还记得当时我们的item中有一个ImageView对吧,我们想通过点击ImageView就可以拖拽item,而目前只能通过长按才能够拖动。
    我们回到RecyclerListFragment中,找到刚才我们还空着的ImageView的onTouch方法

     holder.handle.setOnTouchListener(new View.OnTouchListener() {
                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    return false;
                }
            });

    在onTouch方法中,我们应该回调RecyclerListFragment类中的mItemTouchHelper,调用mItemTouchHelper的onStartDrag方法,因此我们又需要一个回调接口

    public interface onStartDragListener {
        void startDrag(RecyclerView.Adapter adapter);
    }

    我们让RecyclerListFragment实现此接口并且重写startDrag方法

     @Override
        public void startDrag(RecyclerView.ViewHolder viewHolder) {
            mItemTouchHelper.startDrag(viewHolder);
        }

    我们应该将实现了onStartDragListener接口的RecyclerListFragment对象传给RecyclerViewAdapter,那么我们就要在RecyclerViewAdapter的构造方法中添加一个参数

     public RecyclerViewAdapter(Context context , onStartDragListener startDragListener){
            //初始化数据
            mItems.addAll(Arrays.asList(context.getResources().getStringArray(R.array.dummy_items)));
            mStartDragListener = startDragListener;
        }

    接着在ImageView的onTouch方法中做如下操作

      holder.handle.setOnTouchListener(new View.OnTouchListener() {
                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    //如果按下
                    if (MotionEventCompat.getActionMasked(event) == MotionEvent.ACTION_DOWN){
                        //回调RecyclerListFragment中的startDrag方法
                        //让mItemTouchHelper执行拖拽操作
                        mStartDragListener.startDrag(holder);
                    }
                    return false;
                }
            });

    好了,现在我们可以通过拖动item右侧的ImageView来拖拽整个item了
    这里写图片描述
    这里写图片描述

    2.拖拽item时改变item的背景颜色

    我们来到SimpleItemTouchHelperCallback中,重写onSelectedChanged这个回调方法

    /**当状态改变时回调此方法*/
        @Override
        public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
            //当前状态不是idel(空闲)状态时,说明当前正在拖拽或者侧滑
            if (actionState != ItemTouchHelper.ACTION_STATE_IDLE){
                //TODO 改变item的背景颜色
            }
            super.onSelectedChanged(viewHolder, actionState);
        }

    改变item的背景颜色我们仍然需要在adapter中去做实际的修改,因此我们还需要一个回调接口,我们已经写了3个回调接口了

    public interface onStateChangedListener {
        void onItemSelected();
    }

    我们应该让谁来实现这个接口并且重写onItemSelected方法呢?我们看到onSelectedChanged方法中第一个参数是RecyclerView.ViewHolder。 其实在RecyclerView.ViewHolder中有个成员参数itemView,他就是我们item的布局,我们修改item的背景颜色直接修改itemView的背景颜色就可以了,所以我们让我们的ViewHolder实现这个接口

     public static class ItemViewHolder extends RecyclerView.ViewHolder 
                    implements onStateChangedListener{
            private TextView text;
            private ImageView handle;
            public ItemViewHolder(View itemView) {
                super(itemView);
                text = (TextView) itemView.findViewById(R.id.text);
                handle = (ImageView) itemView.findViewById(R.id.handle);
            }
    
            @Override
            public void onItemSelected() {
                //设置item的背景颜色为浅灰色
                itemView.setBackgroundColor(Color.LTGRAY);
            }
        }

    我们来完善onSelectedChanged方法

    /**当状态改变时回调此方法*/
        @Override
        public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
            //当前状态不是idel(空闲)状态时,说明当前正在拖拽或者侧滑
            if (actionState != ItemTouchHelper.ACTION_STATE_IDLE){
                //看看这个viewHolder是否实现了onStateChangedListener接口
                if (viewHolder instanceof onStateChangedListener){
                    onStateChangedListener listener = (onStateChangedListener)viewHolder;
                    //回调ItemViewHolder中的onItemSelected方法来改变item的背景颜色
                    listener.onItemSelected();
                }
            }
            super.onSelectedChanged(viewHolder, actionState);
        }

    运行一下看看效果
    这里写图片描述
    有点问题,我们发现每个item的背景颜色不会自动变回原来的颜色,所以我们还得再手动改回他的背景颜色,所以我们再在onStateChangedListener接口中添加一个方法,用于当拖拽结束后回调修改item背景颜色

    public interface onStateChangedListener {
        void onItemSelected();
        void onItemClear();
    }

    然后在ItemViewHolder中重写onItemClear方法

      @Override
            public void onItemClear() {
                //恢复item的背景颜色
                itemView.setBackgroundColor(0);
            }

    同时,我们还得在SimpleItemTouchHelperCallback中再重写一个clearView方法

     /**当用户拖拽完或者侧滑完一个item时回调此方法,用来清除施加在item上的一些状态*/
        @Override
        public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
            super.clearView(recyclerView, viewHolder);
            if (viewHolder instanceof onStateChangedListener){
                onStateChangedListener listener = (onStateChangedListener)viewHolder;
                listener.onItemClear();
            }
        }

    我们再来看一下效果
    这里写图片描述

    3.侧滑删除时item的颜色逐渐变浅

    我们希望在侧滑删除一个item的时候有一种颜色逐渐变浅的效果,这个效果我们要借助SimpleItemTouchHelperCallback的onChildDraw方法

    /**这个方法可以判断当前是拖拽还是侧滑*/
        @Override
        public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
            if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE){
                //根据侧滑的位移来修改item的透明度
                final float alpha = ALPHA_FULL - Math.abs(dX) / (float) viewHolder.itemView.getWidth();
                viewHolder.itemView.setAlpha(alpha);
                viewHolder.itemView.setTranslationX(dX);
            }
            super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
        }

    我们来看一下效果
    这里写图片描述

    结束语

    这个项目我们学习完了,通过这个项目我们真的可以学到很多东西,比如Fragment的使用,RecyclerView的使用,ItemTouchHelper的使用,回调接口的使用等等。一个好的项目值得我们去仔细推敲。

    展开全文
  • 精致的H5 列表侧滑组件。H5页面侧滑删除、修改的效果。这里只支持手机端访问,Chrome浏览器调试 切换Mobile 调试模式 学习无止境,何时是终点、时间让人沉思。代码分享,是对以下文章的更新版本!...
  • RecyclerView侧滑菜单,RecyclerView滑动删除,RecyclerView长按拖拽,RecyclerView下拉刷新上拉加载 版权声明:转载必须注明本文转自严振杰的博客: http://blog.csdn.net/yanzhenjie1003 RecyclerView侧滑菜单,...
  • OpenCV 删除轮廓的方法(一)

    千次阅读 2016-12-20 17:51:43
    是我刚刚学习到的一个方法,在这之前,如果我想删除一个不需要的轮廓,用的方法是将该轮廓填充为背景色,之前的博客提到过,在countours容器中,如果把轮廓填充为背景色,那么只是视觉上看不到该轮廓,但是实际上还...
  • Docker本地 images 删除方法

    万次阅读 2019-01-12 10:49:40
    背景 测试环境和生产环境 部署了不同的registry服务,通过cli 操作过生产环境或测试环境push/pull ...原因:docker rmi 加-f,只能删除无tag的镜像 ;被曾经打过多处tag(被tag引用),无法直接删除,需要先删...
  • 一、使用背景 总所周知,在日常开发中,我们需要把测试服务器和正式服务器分开。相应的,为了保持正式版本能正常运行,我们需要新建一个git分支用来专门的存放正式版APP的源码。 这样,每当我们生成一个版本的时候...
  • 作者 | 声东 阿里云售后技术专家 导读:阿里云售后技术团队的同学,每天都在处理各式各样千奇百怪的线上问题。常见的有网络连接失败、服务器宕机、性能达标及请求响应慢等。但如果要评选的话,什么...背景 今...
  • 如果上两篇对RecyclerView介绍后,依然没有引起你的兴趣,那么下面关于RecyclerView的使用我相信一定会让你如获珍宝。列表Item拖拽删除以及拖拽切换位置的交互,在这里都可以看见。
  • UltraEdit是一套功能强大的文本编辑器,可以编辑文本、十六进制、ASCII码,可以取代记事本,内建英文单字检查、C++及VB指令突显,可同时编辑多个文件,而且即使开启很大的文件速度也不会慢。软件附有HTML标签颜色显示、...
  • 使用OpenCV实现这一功能:对图像进行二值化分割,并用“红色矩形”标记连通区域的面积,为了减少噪声的干扰,删除面积小的区域,代码中将连通区域面积(像素个数)不足100的区域认为是噪声点,并将其删除(即置为...
  • webStorm 3.0配置使用主题背景色等

    万次阅读 2016-05-07 09:02:11
    编辑类软件层出群,各有所长,各有所短。找到一个合适的还真是难。还好有webstorm的出现,最近又是3.0的新版本发布。为什么这么说呢,她与其它的编辑器有什么不同: 1. 任何一个编辑器都需要保存(ctrl + s),这是...
  • iOS11之前,自定义删除按钮Native定制TableViewCell的删除视图////找到系统中删除按钮对应的类型UITableViewCellDeleteConfirmationView去自定义的cell里面 找到并修改此view样式@implementation SCTableViewCell ...
  • Windows 10 Windows聚焦图片更新 功能失效

    万次阅读 热门讨论 2018-02-07 17:58:26
    在使用系统一段时间或是重置后,可能存在该功能无法正常工作(个性化-锁屏界面中的设置没有变更,始终保持Windows聚焦的状态) 解决方案: Win+S后输入Powershell,右键以管理员身份运行 使用Get-AppxPackage...
  • 基于OpenCV-python3实现抠图&替换背景

    万次阅读 多人点赞 2017-08-04 16:12:55
    简述在上一篇博客进行了证件照更换背景颜色,纯蓝色,红色,白色之间的替换,有人私信我,可以可以把背景换成其他图片,而不是单纯的颜色填充。这在photoshop里面就是选中一个图层然后复制另外一张图片上去,用...
  • 前言:上周末去看房,CAO,累的都快残废了,也没有满意的,害的博客也没写好……,买了…… 相关文章: 1、《 ListView滑动删除实现之一——merge标签与LayoutInflater.inflate()》 2、《ListView滑动删除...
  • 背景:小黑开发cocos2dx游戏,开发完成,接某游戏平台SDK打包APK以实现游戏计费及平台相关功能。 按SDK文档做:把SDK的jar文件都拷贝安卓项目下的libs目录下, 把SDK的so文件都拷贝安卓项目下的libs对应目录下...
  • Docker本地images删除问题

    万次阅读 2017-02-27 16:29:09
    背景测试环境和生产环境 部署了不同的registry服务,通过cli 操作过生产环境或测试环境push/pull image功能。本地虚拟机,docker image 残留了很多image ,现在想删除掉,发现有一个imageid(e9d3f7300f03)无法...
  • idea恢复主题/背景颜色设置(一步搞定,安全)

    万次阅读 多人点赞 2019-08-04 12:05:49
    背景:因自己当初刚接触想idea...太危险,担心把其他设置也删除,就没尝试),后来自己网上实在找不到其他方法了,就自己一点一点的把所有设置color或者主题的选项都点了一遍.最后终于找到了; 把最终方法说一下,希望对你...
  • 【Python学习 】Python实现的FTP上传和下载功能

    万次阅读 多人点赞 2018-02-06 15:49:11
    一、背景 最近公司的一些自动化操作需要使用Python来实现FTP的上传和下载功能。因此参考网上的例子,撸了一段代码来实现了该功能,下面做个记录。 二、ftplib介绍 Python中默认安装的ftplib模块定义了FTP类,...
  • 然后用修补工具框选文字,拖动无文字区域中色彩  或图案相似的位置,松开鼠标就完成复制。修补工具具有自动匹配颜  色的功能,复制出的效果与周围的色彩较为融合,这是仿制图章工具  所具备的。 ...
  • 使用SQLServer 2008的CDC功能实现数据变更捕获

    万次阅读 多人点赞 2012-10-30 23:35:53
    背景: 在SQLServer2008之前,对数据变更的捕获通常使用触发器、时间戳等低效高成本的功能来实现,所以很多系统都没有做数据变更或者仅仅对核心表做监控。 自从SQLServer2008引入了数据变更捕获功能(后面简称为
  • 第一次安装sql,遇到了共享功能目录能更改的问题,占用c盘
  • 前言:世人总是恐惧失败,但失败了也大从头再来 相关系列文章: Android自定义控件三部曲文章索引:http://blog.csdn.net/harvic880925/article/details/50995268 前几篇给大家讲了有关绘图的知识,这篇我们稍微...
  • 【java细节】详解如何删除cookie

    万次阅读 2015-10-25 20:05:28
    介绍cookie删除的JAVA实现和JS实现,同时讲解cookie删除不了时候我愿意分析!
  • 一、背景 在做项目的时候,有一个需求,在两级列表中,实现类似于IOS的滑动删除效果,大体如下图: 但有两点太一样的地方:上层界面,是随手势滑动的;下层界面在上层被滑走后露出来。 老大让我实现这...
  • 实战环境: macOS Mojave - 10.14.x 工具: 高清的目标背景图(login-screen-wallpaper.jpg) ...把目标背景图login-screen-... 打开访达(Finder),按下Shift+command+G,唤出“前往文件夹”功能,打开“/Lib...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 153,007
精华内容 61,202
关键字:

删除背景功能找不到