可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I have a custom ListView showing the list of words selecting from database. When I swipe this listview item i want to show Delete button like image below. And when I press that button it is deleted from Database and refresh the listview.
m
I already look in this sample code here. But it still does not work.
回答1:
EDIT:
between other options there's a nice library that could solve your issue:
https://github.com/daimajia/AndroidSwipeLayout
回答2:
i've searched google a lot and find the best suited project is the swipmenulistview https://github.com/baoyongzhang/SwipeMenuListView on github.
回答3:
I used to have the same problem finding a good library to do that. Eventually, I created a library which can do that: SwipeRevealLayout
In gradle file:
dependencies {
compile 'com.chauthai.swipereveallayout:swipe-reveal-layout:1.4.0'
}
In your xml file:
<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>
Then in your adapter file:
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
}
}
回答4:
I had created a demo on my github which includes on swiping from right to left a delete button will appear and you can then delete your item from the ListView and update your ListView.
回答5:
I just got his working using the ViewSwitcher in a ListItem.
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>
In the ListAdapter:
Implement OnclickListeners for the Edit and Delete button in the getView() method. The catch here is to get the position of the ListItem clicked inside the onClick methods. setTag() and getTag() methods are used for this.
@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;
}
In the Fragment,
Add a Gesture Listener to detect the Fling Gesture:
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;
}
}
In the onCreateView method of the Fragment,
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;
}
}
});
This worked for me. Should refine it more.
回答6:
see there link was very nice and simple. its working fine...
u don't want any library its working fine. click here
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;
}
};
回答7:
An app is available that demonstrates a listview that combines both swiping-to-delete and dragging to reorder items. The code is based on Chet Haase's code for swiping-to-delete and Daniel Olshansky's code for dragging-to-reorder.
Chet's code deletes an item immediately. I improved on this by making it function more like Gmail where swiping reveals a bottom view that indicates that the item is deleted but provides an Undo button where the user has the possibility to undo the deletion. Chet's code also has a bug in it. If you have less items in the listview than the height of the listview is and you delete the last item, the last item appears to not be deleted. This was fixed in my code.
Daniel's code requires pressing long on an item. Many users find this unintuitive as it tends to be a hidden function. Instead, I modified the code to allow for a "Move" button. You simply press on the button and drag the item. This is more in line with the way the Google News app works when you reorder news topics.
The source code along with a demo app is available at:
https://github.com/JohannBlake/ListViewOrderAndSwipe
Chet and Daniel are both from Google.
Chet's video on deleting items can be viewed at:
https://www.youtube.com/watch?v=YCHNAi9kJI4
Daniel's video on reordering items can be viewed at:
https://www.youtube.com/watch?v=_BZIvjMgH-Q
A considerable amount of work went into gluing all this together to provide a seemless UI experience, so I'd appreciate a Like or Up Vote. Please also star the project in Github.
回答8:
Define a ViewPager in your layout .xml:
<android.support.v4.view.ViewPager
android:id="@+id/example_pager"
android:layout_width="fill_parent"
android:layout_height="@dimen/abc_action_bar_default_height" />
And then, in your activity / fragment, set a custom pager adapter:
In an activity:
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);
}
In a fragment:
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;
}
Create our custom pager class:
// 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];
}
}
回答9:
It's a lose of time to implement from scratch this functionality.
I implemented the library recommended by SalutonMondo and I am very satisfied.
It is very simple to use and very quick.
I improved the original library and I added a new click listener for item click.
Also I added font awesome library (http://fortawesome.github.io/Font-Awesome/) and now you can simply add a new item title and specify the icon name from font awesome.
Here is the github link
回答10:
I have gone through tons of third party libraries to try to achieve this. But none of them exhibits smoothness and usability experience which i wanted. Then i decided to write it myself. And the result was , well, i loved it. I will share the code here. Maybe i will write it as a library which can be embedded in any recycler view in future. But for now here is the code.
Note: i have uses recycler view and ViewHolder. Some values are hardcoded so change them according to your requirement.
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
public class ChatAdaptor extends 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);
}
}
}
Hope this helps someone!!
回答11:
you can use this code
holder.img_close.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
holder.swipeRevealLayout.close(true);
list.remove(position);
notifyDataSetChanged();
}});