滑动ListView项目从右到左显示删除button

我有一个自定义ListView显示从数据库中select的单词列表。 当我刷这个列表视图项目我想显示删除button像下面的图像。 而当我按下该button,它将从数据库中删除并刷新列表视图。 米 滑动列表视图项目

我已经在这里看这个示例代码。 但它仍然不起作用。

编辑:其他选项之间有一个很好的库,可以解决您的问题: https : //github.com/daimajia/AndroidSwipeLayout

我search了很多谷歌,find最适合的项目是github上的swipmenulistview https://github.com/baoyongzhang/SwipeMenuListView

我曾经有同样的问题find一个好的图书馆来做到这一点。 最后,我创build了一个可以做到的库: SwipeRevealLayout

在gradle文件中:

dependencies { compile 'com.chauthai.swipereveallayout:swipe-reveal-layout:1.4.0' } 

在你的xml文件中:

 <com.chauthai.swipereveallayout.SwipeRevealLayout android:layout_width="match_parent" android:layout_height="match_parent" app:mode="same_level" app:dragEdge="left"> <!-- Your secondary layout here --> <FrameLayout android:layout_width="wrap_content" android:layout_height="match_parent" /> <!-- Your main layout here --> <FrameLayout android:layout_width="match_parent" android:layout_height="match_parent" /> </com.chauthai.swipereveallayout.SwipeRevealLayout> 

然后在你的适配器文件中:

 public class Adapter extends RecyclerView.Adapter { // This object helps you save/restore the open/close state of each view private final ViewBinderHelper viewBinderHelper = new ViewBinderHelper(); @Override public void onBindViewHolder(ViewHolder holder, int position) { // get your data object first. YourDataObject dataObject = mDataSet.get(position); // Save/restore the open/close state. // You need to provide a String id which uniquely defines the data object. viewBinderHelper.bind(holder.swipeRevealLayout, dataObject.getId()); // do your regular binding stuff here } } 

我在我的github上创build了一个演示,其中包括从右向左滑动删除button将出现,然后您可以从ListView中删除您的项目并更新您的ListView。

我只是在ListItem中使用ViewSwitcher工作。

list_item.xml:

 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" > <ViewSwitcher android:id="@+id/list_switcher" android:layout_width="match_parent" android:layout_height="fill_parent" android:inAnimation="@android:anim/slide_in_left" android:outAnimation="@android:anim/slide_out_right" android:measureAllChildren="false" > <TextView android:id="@+id/tv_item_name" android:layout_width="match_parent" android:layout_height="50dp" android:layout_gravity="center_vertical" android:maxHeight="50dp" android:paddingLeft="10dp" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:clickable="false" android:gravity="center" > <Button android:id="@+id/b_edit_in_list" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Edit" android:paddingLeft="20dp" android:paddingRight="20dp" /> <Button android:id="@+id/b_delete_in_list" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Delete" android:paddingLeft="20dp" android:paddingRight="20dp" android:background="@android:color/holo_red_dark" /> </LinearLayout> </ViewSwitcher> 

在ListAdapter中:为getView()方法中的Edit和Deletebutton实现OnclickListeners。 这里的catch是获取在onClick方法中点击的ListItem的位置。 setTag()和getTag()方法用于此。

 @Override public View getView(final int position, View convertView, ViewGroup parent) { // TODO Auto-generated method stub final ViewHolder viewHolder; if (convertView == null) { viewHolder = new ViewHolder(); convertView = mInflater.inflate(R.layout.list_item, null); viewHolder.viewSwitcher=(ViewSwitcher)convertView.findViewById(R.id.list_switcher); viewHolder.itemName = (TextView) convertView .findViewById(R.id.tv_item_name); viewHolder.deleteitem=(Button)convertView.findViewById(R.id.b_delete_in_list); viewHolder.deleteItem.setTag(position); viewHolder.editItem=(Button)convertView.findViewById(R.id.b_edit_in_list); viewHolder.editItem.setTag(position); viewHolder.deleteItem.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub fragment.deleteItemList((Integer)v.getTag()); } }); viewHolder.editItem.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub fragment.editItemList(position); } }); convertView.setTag(viewHolder); } else { viewHolder = (ViewHolder) convertView.getTag(); } viewHolder.itemName.setText(itemlist[position]); return convertView; } 

在片段中,添加一个手势监听器来检测飞掷手势:

 public class MyGestureListener extends SimpleOnGestureListener { private ListView list; public MyGestureListener(ListView list) { this.list = list; } // CONDITIONS ARE TYPICALLY VELOCITY OR DISTANCE @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { // if (INSERT_CONDITIONS_HERE) ltor=(e2.getX()-e1.getX()>DELTA_X); if (showDeleteButton(e1)) { return true; } return super.onFling(e1, e2, velocityX, velocityY); } @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { // TODO Auto-generated method stub return super.onScroll(e1, e2, distanceX, distanceY); } private boolean showDeleteButton(MotionEvent e1) { int pos = list.pointToPosition((int) e1.getX(), (int) e1.getY()); return showDeleteButton(pos); } private boolean showDeleteButton(int pos) { View child = list.getChildAt(pos); if (child != null) { Button delete = (Button) child .findViewById(R.id.b_edit_in_list); ViewSwitcher viewSwitcher = (ViewSwitcher) child .findViewById(R.id.host_list_switcher); TextView hostName = (TextView) child .findViewById(R.id.tv_host_name); if (delete != null) { viewSwitcher.setInAnimation(AnimationUtils.loadAnimation(getActivity(), R.anim.slide_in_left)); viewSwitcher.setOutAnimation(AnimationUtils.loadAnimation(getActivity(), R.anim.slide_out_right)); } viewSwitcher.showNext(); // frameLayout.setVisibility(View.VISIBLE); } return true; } return false; } } 

在Fragment的onCreateView方法中,

 GestureDetector gestureDetector = new GestureDetector(getActivity(), new MyGestureListener(hostList)); hostList.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { // TODO Auto-generated method stub if (gestureDetector.onTouchEvent(event)) { return true; } else { return false; } } }); 

这对我有效。 应该更细化它。

看到那里的链接是非常好的,简单的。 它的工作正常…你不希望任何图书馆工作正常。 点击这里

 OnTouchListener gestureListener = new View.OnTouchListener() { private int padding = 0; private int initialx = 0; private int currentx = 0; private ViewHolder viewHolder; public boolean onTouch(View v, MotionEvent event) { if ( event.getAction() == MotionEvent.ACTION_DOWN) { padding = 0; initialx = (int) event.getX(); currentx = (int) event.getX(); viewHolder = ((ViewHolder) v.getTag()); } if ( event.getAction() == MotionEvent.ACTION_MOVE) { currentx = (int) event.getX(); padding = currentx - initialx; } if ( event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL) { padding = 0; initialx = 0; currentx = 0; } if(viewHolder != null) { if(padding == 0) { v.setBackgroundColor(0xFF000000 ); if(viewHolder.running) v.setBackgroundColor(0xFF058805); } if(padding > 75) { viewHolder.running = true; v.setBackgroundColor(0xFF00FF00 ); viewHolder.icon.setImageResource(R.drawable.clock_running); } if(padding < -75) { viewHolder.running = false; v.setBackgroundColor(0xFFFF0000 ); } v.setPadding(padding, 0,0, 0); } return true; } }; 

在布局.xml中定义一个ViewPager:

 <android.support.v4.view.ViewPager android:id="@+id/example_pager" android:layout_width="fill_parent" android:layout_height="@dimen/abc_action_bar_default_height" /> 

然后,在您的activity / fragment中,设置一个自定义寻呼机适配器:

在一个活动中:

 protected void onCreate(Bundle savedInstanceState) { PagerAdapter adapter = new PagerAdapter(getSupportFragmentManager()); ViewPager pager = (ViewPager) findViewById(R.id.example_pager); pager.setAdapter(adapter); // pager.setOnPageChangeListener(this); // You can set a page listener here pager.setCurrentItem(0); } 

在一个片段中:

 public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_layout, container, false); if (view != null) { PagerAdapter adapter = new PagerAdapter(getSupportFragmentManager()); ViewPager pager = (ViewPager) view.findViewById(R.id.example_pager); pager.setAdapter(adapter); // pager.setOnPageChangeListener(this); // You can set a page listener here pager.setCurrentItem(0); } return view; } 

创build我们的自定义寻呼机类:

 // setup your PagerAdapter which extends FragmentPagerAdapter class PagerAdapter extends FragmentPagerAdapter { public static final int NUM_PAGES = 2; private CustomFragment[] mFragments = new CustomFragment[NUM_PAGES]; public PagerAdapter(FragmentManager fragmentManager) { super(fragmentManager); } @ Override public int getCount() { return NUM_PAGES; } @ Override public Fragment getItem(int position) { if (mFragments[position] == null) { // this calls the newInstance from when you setup the ListFragment mFragments[position] = new CustomFragment(); } return mFragments[position]; } } 

这是从零开始实现这个function的时间。 我实施了SalutonMondo推荐的图书馆,我非常满意。 使用起来非常简单,而且非常快捷。 我改进了原来的库,我添加了一个新的点击监听器的项目点击。 此外,我添加了字体真棒图书馆( http://fortawesome.github.io/Font-Awesome/ ),现在你可以简单地添加一个新的项目标题,并从字体真棒指定图标名称。

这里是github链接

一个可用的应用程序演示了一个列表视图,该列表视图结合了滑动删除和拖动以重新sorting项目。 该代码基于Chet Haase的用于滑动删除的代码和Daniel Olshansky的拖放到重新sorting的代码。

切特的代码立即删除一个项目。 我改进了这一点,使其function更像Gmail的地方滑动显示底部视图,指示该项目被删除,但提供了一个撤消button,用户有可能撤消删除。 切特的代码也有一个bug。 如果列表视图中的项目less于列表视图的高度,并且您删除了最后一个项目,则最后一个项目似乎不会被删除。 这是在我的代码中修复的。

丹尼尔的代码需要长时间在物品上。 许多用户觉得这是不直观的,因为它往往是一个隐藏的function。 相反,我修改了代码以允许“移动”button。 您只需按下button并拖动该项目。 当您重新sorting新闻主题时,这更符合Google新闻应用程序的工作方式。

源代码以及演示应用程序可在以下位置获得: https : //github.com/JohannBlake/ListViewOrderAndSwipe

切特和丹尼尔都来自Google。

切特关于删除项目的video可在以下url查看: https : //www.youtube.com/watch?v = YCHNAi9kJI4

丹尼尔的重新sorting项目的video可以在以下url查看: https : //www.youtube.com/watch?v = _BZIvjMgH

相当多的工作都融合在一起,以提供一个无与伦比的用户体验,所以我会喜欢赞或投票。 也请在Github上给项目加上星号。

我已经通过了大量的第三方库来尝试实现这一目标。 但是他们没有一个performance出我想要的stream畅性和可用性。 然后我决定自己写。 结果是,我喜欢它。 我将在这里分享代码。 也许我会把它写成一个图书馆,将来可以embedded到任何回收站的视图中。 但现在这里是代码。

注意:我已经使用recycler视图和ViewHolder。 有些值是硬编码的,所以根据您的要求更改它们。

  • row_layout.xml

     <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:orientation="horizontal"> <Button android:id="@+id/slide_button_2" android:text="Button2" android:layout_width="80dp" android:layout_height="80dp" /> <Button android:id="@+id/slide_button_1" android:text="Button1" android:layout_width="80dp" android:layout_height="80dp" /> </LinearLayout> <LinearLayout android:id="@+id/chat_row_cell" android:layout_width="match_parent" android:layout_height="80dp" android:orientation="horizontal" android:background="@color/white"> <ImageView android:id="@+id/chat_image" android:layout_width="60dp" android:layout_height="60dp" android:layout_marginLeft="10dp" android:layout_marginTop="10dp" android:layout_marginBottom="10dp" android:layout_marginRight="10dp" android:layout_gravity="center"/> <LinearLayout android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:gravity="center"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <TextView android:id="@+id/chat_title" android:layout_width="match_parent" android:layout_height="wrap_content" android:textColor="@color/md_grey_800" android:textSize="18sp"/> <TextView android:id="@+id/chat_subtitle" android:layout_width="match_parent" android:layout_height="wrap_content" android:textColor="@color/md_grey_600"/> </LinearLayout> </LinearLayout> </LinearLayout> 
  • ChatAdaptor.java

    公共类ChatAdaptor扩展RecyclerView.Adapter {

     List<MXGroupChatSession> sessions; Context context; ChatAdaptorInterface listener; public interface ChatAdaptorInterface{ void cellClicked(MXGroupChatSession session); void utilityButton1Clicked(MXGroupChatSession session); void utilityButton2Clicked(MXGroupChatSession session); } public ChatAdaptor(List<MXGroupChatSession> sessions, ChatAdaptorInterface listener, Context context){ this.sessions=sessions; this.context=context; this.listener=listener; } @Override public ChatViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view=(View)LayoutInflater.from(parent.getContext()).inflate(R.layout.chat_row,null); ChatViewHolder chatViewHolder=new ChatViewHolder(view); return chatViewHolder; } @Override public void onBindViewHolder(ChatViewHolder holder, final int position) { MXGroupChatSession session=this.sessions.get(position); holder.selectedSession=session; holder.titleView.setText(session.getTopic()); holder.subtitleView.setText(session.getLastFeedContent()); Picasso.with(context).load(new File(session.getCoverImagePath())).transform(new CircleTransformPicasso()).into(holder.imageView); } @Override public int getItemCount() { return sessions.size(); } public class ChatViewHolder extends RecyclerView.ViewHolder{ ImageView imageView; TextView titleView; TextView subtitleView; ViewGroup cell; ViewGroup cellContainer; Button button1; Button button2; MXGroupChatSession selectedSession; private GestureDetectorCompat gestureDetector; float totalx; float buttonTotalWidth; Boolean open=false; Boolean isScrolling=false; public ChatViewHolder(View itemView) { super(itemView); cell=(ViewGroup) itemView.findViewById(R.id.chat_row_cell); cellContainer=(ViewGroup) itemView.findViewById(R.id.chat_row_container); button1=(Button) itemView.findViewById(R.id.slide_button_1); button2=(Button) itemView.findViewById(R.id.slide_button_2); button1.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { listener.utilityButton1Clicked(selectedSession); } }); button2.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { listener.utilityButton2Clicked(selectedSession); } }); ViewTreeObserver vto = cellContainer.getViewTreeObserver(); vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { buttonTotalWidth = button1.getWidth()+button2.getWidth(); } }); this.titleView=(TextView)itemView.findViewById(R.id.chat_title); subtitleView=(TextView)itemView.findViewById(R.id.chat_subtitle); imageView=(ImageView)itemView.findViewById(R.id.chat_image); gestureDetector=new GestureDetectorCompat(context,new ChatRowGesture()); cell.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { if(gestureDetector.onTouchEvent(event)){ return true; } if(event.getAction() == MotionEvent.ACTION_UP) { if(isScrolling ) { isScrolling = false; handleScrollFinished(); }; } else if(event.getAction() == MotionEvent.ACTION_CANCEL){ if(isScrolling ) { isScrolling = false; handleScrollFinished(); }; } return false; } }); } public class ChatRowGesture extends GestureDetector.SimpleOnGestureListener { @Override public boolean onSingleTapUp(MotionEvent e) { if (!open){ listener.cellClicked(selectedSession); } return true; } @Override public boolean onDown(MotionEvent e) { return true; } @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { isScrolling=true; totalx=totalx+distanceX; freescroll(totalx); return true; } } void handleScrollFinished(){ if (open){ if (totalx>2*buttonTotalWidth/3){ slideLeft(); totalx=buttonTotalWidth; }else{ slideRight(); totalx=0; } }else{ if (totalx>buttonTotalWidth/3){ slideLeft(); totalx=buttonTotalWidth; }else{ slideRight(); totalx=0; } } } void slideRight(){ TransitionManager.beginDelayedTransition(cellContainer); ViewGroup.MarginLayoutParams params; params=(ViewGroup.MarginLayoutParams) cell.getLayoutParams(); params.setMargins(0,0,0,0); cell.setLayoutParams(params); open=false; } void slideLeft(){ TransitionManager.beginDelayedTransition(cellContainer); ViewGroup.MarginLayoutParams params; params=(ViewGroup.MarginLayoutParams) cell.getLayoutParams(); params.setMargins(((int)buttonTotalWidth*-1),0,(int)buttonTotalWidth,0); cell.setLayoutParams(params); open=true; } void freescroll(float x){ if (x<buttonTotalWidth && x>0){ int xint=(int)x; ViewGroup.MarginLayoutParams params; params=(ViewGroup.MarginLayoutParams) cell.getLayoutParams(); params.setMargins(params.leftMargin,0,xint,0); cell.setLayoutParams(params); } } } 

希望这可以帮助别人!