简体   繁体   English

如何在ListView中创建Section Header,并滑动以删除具有Undo选项的Item

[英]How to make Section Header in ListView, and Swipe to delete a Item with Undo option

Required: 需要:

1.I want to Make a Sectioned Header Listview in Android. 1.我想在Android中创建一个分段标题列表视图。

2.That should be Swipe to delete a item, with Undo option like Gmail App.but Gmail App not contains Section Header. 2.应该使用“滑动”来删除项目,使用“撤消”选项,例如Gmail App。但Gmail应用程序不包含“部分标题”。

3.My Application should be have Section Header. 3.我的应用程序应该有Section Header。

i tried below mentioned link for Swipe to delete along with Undo button. 我尝试下面提到的链接,以删除滑动以及撤消按钮。 its worked perfectly. 它工作得很好。

Problem: 问题:

EDIT :1(ListView) 编辑:1(ListView)

1.i found the code for Swipe to Delete a item with Undo in Listview Link-Swipe to delete a listview item and Section Header Using Listview link-Section header in listview . 1.i 在Listview Link-Swipe中找到了用于滑动以删除具有撤消的项目的代码, 以删除列表视图中的列表视图项截面标题使用Listview 链接 - 节标题

2.both are having two different Base Adapters Iam getting some Error,Please help me to merge that adapters or suggest me any new way to add section Header in Swipe to Delete a Listview items. 2.有两个不同的基本适配器我得到一些错误,请帮我合并适配器或建议我在刷卡中添加部分标题以删除Listview项目的任何新方法。

CODE: Class for Swipe to Delete and Section Header in Listview 代码: 要删除的类和列表视图中的节标题

ListViewActivity.class ListViewActivity.class

package com.data.swipetodeletesimplelistview;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.app.Activity;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;

import static android.widget.Toast.LENGTH_SHORT;
public class ListViewActivity extends AppCompatActivity {

    private static final int TIME_TO_AUTOMATICALLY_DISMISS_ITEM = 3000;

/*For Section header*/
    ListView mListView;
    ArrayList<String> mArrayList = new ArrayList<String>();
    SectionedAdapter adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_list_view);
        init((ListView) findViewById(R.id.list_view));


/*For Section Header Starts Here*/
        mListView = (ListView) findViewById(R.id.list_view);

        adapter = new SectionedAdapter() {

            @Override
            protected View getHeaderView(String caption, int index, View convertView, ViewGroup parent) {
                convertView = getLayoutInflater().inflate(R.layout.section_header, null);
                TextView header = (TextView) convertView.findViewById(R.id.header);
                header.setText(caption);
                return convertView;
            }
        };

        for (int i = 0; i < 5; i++)
        {
            mArrayList.add("Item " + i);
            MyAdapter myAdapter = new MyAdapter();
            adapter.addSection("Header " + i, myAdapter);
        }
        mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {

            public void onItemClick(AdapterView<?> arg0, View arg1, int position, long arg3) {
                Toast.makeText(getApplicationContext(), arg0.getAdapter().getItem(position).toString(), Toast.LENGTH_LONG).show();
            }
        });
        mListView.setAdapter(adapter);

/*For Section Header Ends Here*/
    }
/*FOr Swipe to Delete a item Starts Here*/   
    private void init(ListView listView)
    {
        final MyBaseAdapter adapter = new MyBaseAdapter();
        listView.setAdapter(adapter);
        final SwipeToDismissTouchListener<ListViewAdapter> touchListener =
                new SwipeToDismissTouchListener<>(
                        new ListViewAdapter(listView),
                        new SwipeToDismissTouchListener.DismissCallbacks<ListViewAdapter>() {
                            @Override
                            public boolean canDismiss(int position) {
                                return true;
                            }

                            @Override
                            public void onPendingDismiss(ListViewAdapter recyclerView, int position) {

                            }

                            @Override
                            public void onDismiss(ListViewAdapter view, int position) {
                                adapter.remove(position);
                            }
                        });

        touchListener.setDismissDelay(TIME_TO_AUTOMATICALLY_DISMISS_ITEM);
        listView.setOnTouchListener(touchListener);
        // Setting this scroll listener is required to ensure that during ListView scrolling,
        // we don't look for swipes.
        listView.setOnScrollListener((AbsListView.OnScrollListener) touchListener.makeScrollListener());
        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                if (touchListener.existPendingDismisses()) {
                    touchListener.undoPendingDismiss();
                } else {
                    Toast.makeText(ListViewActivity.this, "Position " + position, LENGTH_SHORT).show();
                }
            }
        });
    }

    /*FOr Swipe to Delete*/
    static class MyBaseAdapter extends BaseAdapter
    {

        private static final int SIZE = 100;

        private final List<String> mDataSet = new ArrayList<>();

        MyBaseAdapter() {
            for (int i = 0; i < SIZE; i++)
                mDataSet.add(i, "This is row number " + i);
        }

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

        @Override
        public String getItem(int position) {
            return mDataSet.get(position);
        }

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

        public void remove(int position) {
            mDataSet.remove(position);
            notifyDataSetChanged();
        }

        static class ViewHolder {
            TextView dataTextView;
            ViewHolder(View view) {
                dataTextView = (TextView) view.findViewById(R.id.txt_data);
                view.setTag(this);
            }
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {

            ViewHolder viewHolder = convertView == null
                    ? new ViewHolder(convertView = LayoutInflater.from(parent.getContext())
                    .inflate(R.layout.list_item, parent, false)) : (ViewHolder) convertView.getTag();

            viewHolder.dataTextView.setText(mDataSet.get(position));
            return convertView;
        }
    }

/*FOr Swipe to Delete a item Ends Here*/

    /*For adding Section header*/
    class MyAdapter extends BaseAdapter
{

        public int getCount()
        {
            return mArrayList.size();
        }

        public Object getItem(int position)
        {
            return mArrayList.get(position);
        }

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

        public View getView(int position, View convertView, ViewGroup parent) {
            convertView = (TextView) getLayoutInflater().inflate(R.layout.section_item, null);
            TextView item = (TextView) convertView.findViewById(R.id.item);
            item.setText(mArrayList.get(position));
            return convertView;
        }
    }
}

You basically wanted to have two type of rows in the list. 您基本上希望列表中有两种类型的行。

  1. Item which will have swipe to delete functionality. 将滑动以删除功能的项目。
  2. Header which will not have swipe functionality. 没有滑动功能的标题。

Create a recyclerView or listView by inflating two different type of layout. 通过膨胀两种不同类型的布局来创建recyclerView或listView。 Check How to create RecyclerView with multiple view type? 检查如何使用多种视图类型创建RecyclerView?

Edit: Swipe to delete, Undo and Sectioned list Adapter issue 编辑:滑动以删除,撤消和分区列表适配器问题

As mentioned by @MadScientist, there should be only one Adapter for the list or recyclerView. 正如@MadScientist所提到的,列表或者recyclerView应该只有一个适配器。 Follow following steps to achieve your requirements: 请按照以下步骤来满足您的要求:

  1. Create a Recycler View to display sectioned header and items. 创建Recycler视图以显示分段标题和项目。
  2. Implement Swipe to delte functionality to your existing list. 实现滑动以将功能删除到现有列表。
  3. Implement undo functionality to your existing list. 对现有列表实施撤消功能。

See below sample code of RecyclerAdapter for sectioned header and undo functionality: 有关分区标题和撤消功能,请参阅下面的RecyclerAdapter示例代码:

public class SectionedRecyclerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    private static final int TYPE_HEADER = 0;
    private static final int TYPE_ITEM = 1;
    private List<SectionedItem> sectionedItemList;
    private List<SectionedItem> itemsPendingRemoval;
    private Context context;

    private static final int PENDING_REMOVAL_TIMEOUT = 3000;
    private Handler handler = new Handler();
    private HashMap<SectionedItem, Runnable> pendingRunnables = new HashMap<>();

    public SectionedRecyclerAdapter(List<SectionedItem> itemList, Context context) {
        this.sectionedItemList = itemList;
        this.context = context;
        itemsPendingRemoval = new ArrayList<>();
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        if (viewType == TYPE_ITEM) {
            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.view_item, parent, false);
            return new SectionedItemViewHolder(view);
        } else if (viewType == TYPE_HEADER) {
            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.view_header, parent, false);
            return new SectionedHeaderViewHolder(view);
        }
        throw new RuntimeException("there is no type that matches the type " + viewType + " + make sure your using types correctly");
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, final int position) {
        if (viewHolder instanceof SectionedItemViewHolder) {
            final SectionedItem data = sectionedItemList.get(position);

            if (itemsPendingRemoval.contains(data)) {
                ((SectionedItemViewHolder) viewHolder).itemLayout.setVisibility(View.GONE);
                ((SectionedItemViewHolder) viewHolder).undoLayout.setVisibility(View.VISIBLE);
                ((SectionedItemViewHolder) viewHolder).undobutton.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
                        undoOpt(data);
                    }
                });
            } else {
                ((SectionedItemViewHolder) viewHolder).itemLayout.setVisibility(View.VISIBLE);
                ((SectionedItemViewHolder) viewHolder).undoLayout.setVisibility(View.GONE);
                ((SectionedItemViewHolder) viewHolder).itemName.setText(sectionedItemList.get(position).itemName);
            }
        }

        if (viewHolder instanceof SectionedHeaderViewHolder) {
            ((SectionedHeaderViewHolder) viewHolder).headerTitle.setText(sectionedItemList.get(position).itemName);
        }
    }

    @Override
    public int getItemCount() {
        return sectionedItemList.size();
    }

    @Override
    public int getItemViewType(int position) {
        if (isPositionHeader(position)) {
            return TYPE_HEADER;
        }
        return TYPE_ITEM;
    }

    private boolean isPositionHeader(int position) {

        return sectionedItemList.get(position).isHeader;
    }

    private void undoOpt(SectionedItem customer) {
        Runnable pendingRemovalRunnable = pendingRunnables.get(customer);
        pendingRunnables.remove(customer);
        if (pendingRemovalRunnable != null)
            handler.removeCallbacks(pendingRemovalRunnable);
        itemsPendingRemoval.remove(customer);
        // this will rebind the row in "normal" state
        notifyItemChanged(sectionedItemList.indexOf(customer));
    }

    public void pendingRemoval(int position) {

        final SectionedItem data = sectionedItemList.get(position);
        if (!itemsPendingRemoval.contains(data) && !data.isHeader) {
            itemsPendingRemoval.add(data);
            // this will redraw row in "undo" state
            notifyItemChanged(position);
            // let's create, store and post a runnable to remove the data
            Runnable pendingRemovalRunnable = new Runnable() {
                @Override
                public void run() {
                    remove(sectionedItemList.indexOf(data));
                }
            };
            handler.postDelayed(pendingRemovalRunnable, PENDING_REMOVAL_TIMEOUT);
            pendingRunnables.put(data, pendingRemovalRunnable);
        }
    }

    public void remove(int position) {
        SectionedItem data = sectionedItemList.get(position);
        if (itemsPendingRemoval.contains(data)) {
            itemsPendingRemoval.remove(data);
        }
        if (sectionedItemList.contains(data)) {
            sectionedItemList.remove(position);
            notifyItemRemoved(position);
        }
    }

    private void removeItemPermanently(int position) {
        sectionedItemList.get(position).isSoftDeleted = false;
        sectionedItemList.remove(position);
        notifyItemRemoved(position);
    }

    public boolean isPendingRemoval(int position) {
        SectionedItem data = sectionedItemList.get(position);
        return (itemsPendingRemoval.contains(data) || data.isHeader);
    }
}

I have used link as reference to implement undo bar 我使用链接作为参考来实现撤消栏

Add SwipeUtil.java class as it is from the above link and update your Activity class like below: Add this function to your Activity class 从上面的链接添加SwipeUtil.java类并更新您的Activity类,如下所示:将此函数添加到您的Activity类

private void setSwipeForRecyclerView() {

        SwipeUtils swipeHelper = new SwipeUtils(0, ItemTouchHelper.LEFT, ActivityB.this) {
            @Override
            public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
                int swipedPosition = viewHolder.getAdapterPosition();
                SectionedRecyclerAdapter adapter = (SectionedRecyclerAdapter) sectionedList.getAdapter();
                adapter.pendingRemoval(swipedPosition);
            }

            @Override
            public int getSwipeDirs(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
                int position = viewHolder.getAdapterPosition();
                SectionedRecyclerAdapter adapter = (SectionedRecyclerAdapter) sectionedList.getAdapter();
                if (adapter.isPendingRemoval(position)) {
                    return 0;
                }
                return super.getSwipeDirs(recyclerView, viewHolder);
            }
        };

        ItemTouchHelper mItemTouchHelper = new ItemTouchHelper(swipeHelper);
        mItemTouchHelper.attachToRecyclerView(sectionedList);

        //set swipe label
        swipeHelper.setLeftSwipeLable("Deleted");
        //set swipe background-Color
        //swipeHelper.setLeftcolorCode(ContextCompat.getColor((), R.color.swipebg));

    }

And use below code to create the list: 并使用下面的代码来创建列表:

 sectionedList = (RecyclerView)findViewById(R.id.sectioned_list);
 RecyclerView.LayoutManager layoutManager= new LinearLayoutManager(this);
 sectionedList.setLayoutManager(layoutManager);
 final SectionedRecyclerAdapter sectionedRecyclerAdapter = new SectionedRecyclerAdapter(itemList, this);

 sectionedList.setAdapter(sectionedRecyclerAdapter);
 setSwipeForRecyclerView();

Edit2: ViewHolders Edit2:ViewHolders

public class SectionedItemViewHolder extends RecyclerView.ViewHolder{
    public TextView itemName;
    public TextView undobutton;
    public View itemLayout;
    public View undoLayout;

    public SectionedItemViewHolder(View itemView) {
        super(itemView);
        itemName = (TextView)itemView.findViewById(R.id.item_title);
        undobutton = (TextView) itemView.findViewById(R.id.txt_undo);
        itemLayout = itemView.findViewById(R.id.item_layout);
        undoLayout = itemView.findViewById(R.id.undo_layout);
    }
}

public class SectionedHeaderViewHolder extends RecyclerView.ViewHolder{
    public TextView headerTitle;

    public SectionedHeaderViewHolder(View itemView) {
        super(itemView);
        headerTitle = (TextView)itemView.findViewById(R.id.header_title);
    }
}

please use this link to implement section recycle view in android 请使用此链接在android中实现section recycle view

http://android-pratap.blogspot.in/2015/12/sectioned-recyclerview-in-android_1.html http://android-pratap.blogspot.in/2015/12/sectioned-recyclerview-in-android_1.html

Didnt get the question much, but if what is needed is this 没有得到很多问题,但如果需要的是这个

Header view not swipe-able but content view swipe-able and an undo bar there then, 标题视图无法刷卡但内容视图可以滑动,然后还有一个撤消栏,

You do not need 2 adapters, Just one RecyclerView adapter will do, with two different view types, as answered by: @nnn 你不需要2个适配器,只有一个RecyclerView适配器可以使用两种不同的视图类型,如下所示:@nnn
But in your SimpleItemCallback implementation, modify the RecyclerView position you do not need the callback to work on by doing the following: 但是在SimpleItemCallback实现中,通过执行以下操作修改您不需要回调的RecyclerView位置:

ItemTouchHelper.SimpleCallback simpleCallback = new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.RIGHT | ItemTouchHelper.LEFT) {
            @Override
            public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
                return false;
            }

            @Override
            public int getSwipeDirs(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
// check for the position you do not want the ItemTouchHelper to work 
//and make it return 0;
                if (viewHolder.getAdapterPosition() == 0)
                    return 0;
                else
                    return super.getSwipeDirs(recyclerView, viewHolder);
            }

            @Override
            public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
// perform delete operation and undo bar operation here.                 

}
            };
            ItemTouchHelper itemTouchHelper = new ItemTouchHelper(simpleCallback);
            itemTouchHelper.attachToRecyclerView(recyclerView);

FYI: A good library for undobar: com.cocosw:undobar:1.+@aar 仅供参考:一个很好的unobar图书馆:com.cocosw:undobar:1。+ @ aar

RecyclerView Adapter code skeleton: RecyclerView适配器代码骨架:

public class Adapter_HeaderView extends RecyclerView.Adapter<Adapter_HeaderView.ViewHolder> {
    private final int VIEW_TYPE_HEADER = 1, VIEW_TYPE_CONTENT = 2;
    private Context context;
    private List<Object> list;

    //    private int meanPercentage;
    public Adapter_HeaderView(Context context, List<Object> list) {
        this.context = context;
        this.list = list;
//        this.meanPercentage =meanPercentage;
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        int layoutID;
        switch (viewType) {
            case VIEW_TYPE_CONTENT:
                // content row layout
                layoutID = R.layout.row_list;
                break;
            case VIEW_TYPE_HEADER:
                // header row layout
                layoutID = R.layout.row_list_header;
                break;
            default:
                layoutID = R.layout.row_list;
                break;

        }
        return new ViewHolder(LayoutInflater.from(context).inflate(layoutID, parent, false));
    }
// override the getItemViewType to return position based on position
    @Override
    public int getItemViewType(int position) {
        if (position == 0) {
            return VIEW_TYPE_HEADER;
        } else
            return VIEW_TYPE_CONTENT;
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, final int position) {
        if (getItemViewType(position) != VIEW_TYPE_HEADER) {
          // load content layout here
          // access all items of list as list.get(position-1); as dummy item added as the first element
        } else {
        // load header layout components here. 
          }
    }

    @Override
    public int getItemCount() {
        // add a dummy item in item count which will be the recycler view header. 
        return list.size() + 1;
    }

    public class ViewHolder extends RecyclerView.ViewHolder {
        public ViewHolder(View itemView) {
            super(itemView);
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM