J'ai un ListView personnalisé montrant la liste des mots sélectionnant dans la base de données. Lorsque je balaie cet élément de liste, je souhaite afficher le bouton Supprimer comme l'image ci-dessous. Et lorsque j'appuie sur ce bouton, il est supprimé de la base de données et actualise la liste. m
Je regarde déjà dans cet exemple de code ici . Mais cela ne fonctionne toujours pas.
EDIT: entre d’autres options, il existe une belle bibliothèque qui pourrait résoudre votre problème: https://github.com/daimajia/AndroidSwipeLayout
j'ai beaucoup cherché sur google et je trouve que le projet le mieux adapté est le swipmenulistview https://github.com/baoyongzhang/SwipeMenuListView sur github.
J'avais le même problème à trouver une bonne bibliothèque pour le faire. Finalement, j'ai créé une bibliothèque qui peut faire ça: SwipeRevealLayout
En fichier de classement:
dependencies {
compile 'com.chauthai.swipereveallayout:swipe-reveal-layout:1.4.0'
}
Dans votre fichier 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>
Puis dans votre fichier d'adaptateur:
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
}
}
J'avais créé un démo sur mon github qui inclut lors du balayage de droite à gauche un bouton de suppression apparaît. Vous pouvez ensuite supprimer votre élément de la liste et mettre à jour votre liste.
Je viens juste de le faire travailler avec ViewSwitcher dans un 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>
Dans le ListAdapter: Implémentez OnclickListeners pour les boutons Editer et Supprimer de la méthode getView (). Le problème ici est d'obtenir la position du ListItem cliqué dans les méthodes onClick. Les méthodes setTag () et getTag () sont utilisées à cet effet.
@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;
}
Dans le fragment, ajoutez un auditeur de geste pour détecter le geste
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;
}
}
Dans la méthode onCreateView du 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;
}
}
});
Cela a fonctionné pour moi. Devrait le raffiner plus.
voir là le lien était très gentil et simple. ça marche bien ... vous ne voulez pas que la bibliothèque marche bien. cliquez ici
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;
}
};
Une application est disponible qui illustre une vue en liste qui combine un glissement pour supprimer et un glissement pour réorganiser les éléments. Le code est basé sur le code de Chet Haase pour le balayage à supprimer et le code de Daniel Olshansky pour le glissement à la commande.
Le code de Chet supprime immédiatement un élément. J'ai amélioré cette fonctionnalité en la faisant ressembler davantage à Gmail, où le balayage révèle une vue de dessous indiquant que l'élément est supprimé, mais fournit un bouton Annuler où l'utilisateur a la possibilité d'annuler la suppression. Le code de Chet a aussi un bug. Si vous avez moins d'éléments dans la vue de liste que la hauteur de celle-ci et que vous supprimez le dernier élément, le dernier élément semble ne pas être supprimé. Cela a été corrigé dans mon code.
Le code de Daniel nécessite d'appuyer longuement sur un élément. De nombreux utilisateurs trouvent cela peu intuitif car il s'agit généralement d'une fonction cachée. Au lieu de cela, j'ai modifié le code pour permettre un bouton "Déplacer". Vous appuyez simplement sur le bouton et faites glisser l'élément. Cela correspond davantage au fonctionnement de l'application Google Actualités lorsque vous réorganisez des sujets d'actualité.
Le code source ainsi qu'une application de démonstration sont disponibles à l'adresse suivante: https://github.com/JohannBlake/ListViewOrderAndSwipe
Chet et Daniel sont tous deux de Google.
La vidéo de Chet sur la suppression d'éléments peut être visionnée à l'adresse suivante: https://www.youtube.com/watch?v=YCHNAi9kJI4
La vidéo de Daniel sur la réorganisation des articles peut être visionnée à l'adresse suivante: https://www.youtube.com/watch?v=_BZIvjMgH-Q
Une quantité considérable de travail a été consacrée au collage de tout cela afin de fournir une expérience d'interface utilisateur sans faille. J'apprécierais donc un vote similaire ou positif. S'il vous plaît également démarrer le projet à Github.
C'est une perte de temps que de mettre en œuvre cette fonctionnalité à partir de zéro. J'ai implémenté la bibliothèque recommandée par SalutonMondo et j'en suis très satisfait. C'est très simple à utiliser et très rapide. J'ai amélioré la bibliothèque d'origine et j'ai ajouté un nouvel écouteur de clic pour l'élément clic. J'ai aussi ajouté une bibliothèque de polices géniales ( http://fortawesome.github.io/Font-Awesome/ ) et vous pouvez désormais ajouter simplement un nouveau titre et spécifier le nom de l'icône à partir de la police géniale.
Ici est le lien github
J'ai parcouru des tonnes de bibliothèques tierces pour tenter d'atteindre cet objectif. Mais aucun d’entre eux ne présente l’expérience de finesse et d’utilisation que je souhaitais. Puis j'ai décidé de l'écrire moi-même. Et le résultat était, eh bien, j'ai adoré. Je vais partager le code ici. Peut-être que je l'écrirai comme une bibliothèque pouvant être intégrée dans n'importe quelle vue de recycleur à l'avenir. Mais pour l'instant voici le code.
Remarque: j'ai utilise recycler view et ViewHolder. Certaines valeurs sont codées en dur, changez-les donc selon vos besoins.
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
classe publique ChatAdaptor étend 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);
}
}
}
J'espère que cela aide quelqu'un !!
Définissez un ViewPager dans votre mise en page .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" />
Et ensuite, dans votre activité/fragment, définissez un adaptateur de pageur personnalisé:
Dans une activité:
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);
}
Dans un 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;
}
Créez notre classe de pager personnalisée:
// 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];
}
}