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

时间:2017-02-21 10:30:02

标签: android listview android-arrayadapter sectionheader

必需:

1.我想在Android中创建一个分段标题列表视图。

2.应使用“滑动”删除项目,使用“撤消”选项,例如Gmail应用。但Gmail应用不包含“部分标题”。

3.我应用程序应该有Section Header。

我尝试了下面提到的链接,用于滑动删除以及撤消按钮。它工作得很好。

问题:

编辑:1(ListView)

1.i找到了滑动以在列表视图中删除具有撤消的项目 Link-Swipe to delete a listview item使用列表视图的部分标题 link-Section header in listview的代码。< / p>

2.两个不同的基本适配器我得到一些错误,请帮我合并那些适配器或建议我在刷卡中添加部分标题以删除Listview项目的任何新方法。< / p>

CODE: 要移除的滑动类和Listview中的截面标题

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;
        }
    }
}

3 个答案:

答案 0 :(得分:4)

您基本上希望列表中有两种类型的行。

  1. 将滑动以删除功能的项目。
  2. 不具有滑动功能的标题。
  3. 通过膨胀两种不同类型的布局来创建recyclerView或listView。 查看How to create RecyclerView with multiple view type?

    编辑:滑动以删除,撤消和分区列表适配器问题

    如@MadScientist所述,列表或recyclerView应该只有一个适配器。 请按照以下步骤来满足您的要求:

    1. 创建一个Recycler View以显示分段标题和项目。
    2. 实施滑动以将功能删除到现有列表。
    3. 对现有列表实施撤消功能。
    4. 有关分区标题和撤消功能,请参阅下面的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);
          }
      }
      

      我使用过link as reference to implement undo bar

      从上面的链接添加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));
      
          }
      

      使用以下代码创建列表:

       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

      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);
          }
      }
      

答案 1 :(得分:2)

请使用此链接在android

中实现部分回收视图

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

答案 2 :(得分:1)

Didnt得到的问题很多,但如果需要的是这个

  

页眉视图无法刷卡但内容视图可以滑动,并且还有一个撤消栏   那么,

您不需要2个适配器, 只有一个RecyclerView适配器可以使用两种不同的视图类型,如下所示:@nnn
但是在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);

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

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);
        }
    }
}