从右向左滑动 ListView 项目显示删除按钮

我有一个自定义 ListView,显示从数据库中选择的单词列表。当我滑动这个列表视图项目,我想显示删除按钮如下图。当我按下该按钮时,它将从数据库中删除并刷新列表视图。 M < img src = “ https://i.stack.imgur.com/aB55l.png”alt = “ SwipListview item”>

我已经查看了这个示例代码 给你。但它仍然不工作。

199396 次浏览

编辑: 在其他选择之间,有一个不错的图书馆可以解决你的问题: Https://github.com/daimajia/androidswipelayout

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

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

我已经创建了一个 在我的 Github 上展示,其中包括从右向左滑动一个删除按钮将出现,然后您可以删除您的项目从列表视图和更新您的列表视图。

在 layout.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" />

然后,在您的活动/片段中,设置一个定制的页导航适配器:

在一项活动中:

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

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

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

我搜索了谷歌很多,发现最适合的项目是在 github 上的 swipmenulistview https://github.com/baoyongzhang/SwipeMenuListView

从头开始实现这个功能会浪费时间。 我实现了 SalutonMondo 推荐的库,我非常满意。 这是非常简单的使用和非常快速。 我改进了原来的库,并为项目单击添加了一个新的单击监听器。 此外,我增加了字体可怕的库(http://fortawesome.github.io/Font-Awesome/) ,现在你可以简单地添加一个新的项目标题,并指定图标名称从字体可怕。

这里 是 github 链接

我只是使用 ListItem 中的 ViewSwitch 让他工作。

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>

在列表适配器中: 在 getView ()方法中为 Edit and Delete 按钮实现 OnclickListener。这里的捕获是获取单击的 ListItem 在 onClick 方法中的位置。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;
}
}

在片段的 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;
}


}
});

这个对我有用,应该再精炼一下。

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

Chet 的代码会立即删除一个项目。我改进了这个功能,让它的功能更像 Gmail,滑动显示一个底部视图,表明项目被删除,但提供了一个撤销按钮,用户有可能撤销删除。Chet 的代码也有一个 bug。如果列表视图中的项少于列表视图的高度,并且删除了最后一个项,则似乎不会删除最后一个项。这在我的代码中是固定的。

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

源代码和演示应用程序可以在: Https://github.com/johannblake/listvieworderandswipe

切特和丹尼尔都来自谷歌。

查特有关删除项目的短片可于以下网址浏览: Https://www.youtube.com/watch?v=ychnai9kji4

丹尼尔关于重新订购物品的视频可以在以下网址浏览: Https://www.youtube.com/watch?v=_bzivjmgh-q

为了提供一个看起来不怎么样的用户界面体验,我花费了大量的工作,所以我希望看到一个“赞”或者“向上投票”。也请在 Github 中启动该项目。

我曾经遇到过同样的问题,找一个好的图书馆来做这件事。最终,我创建了一个可以做到这一点的库: 滑动显示布局

档案:

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

为了实现这个目标,我已经使用了大量的第三方库。但它们都没有展现出我想要的流畅性和可用性体验。然后我决定自己写。结果是,我很喜欢。我会在这里共享代码。也许我会写它作为一个图书馆,可以嵌入在任何回收者的意见,在未来。但现在这里是代码。

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

  • Row _ lay.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 扩展回收视图

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

Hope this helps someone!!

你可以用这个代码

holder.img_close.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
holder.swipeRevealLayout.close(true);
list.remove(position);
notifyDataSetChanged();
}});