web-dev-qa-db-fra.com

Balayer l'élément de liste d'affichage De droite à gauche, afficher le bouton de suppression

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. mSwipe Listview item

Je regarde déjà dans cet exemple de code ici . Mais cela ne fonctionne toujours pas.

68
user3098538

EDIT: entre d’autres options, il existe une belle bibliothèque qui pourrait résoudre votre problème: https://github.com/daimajia/AndroidSwipeLayout

36
Luciano Rodríguez

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.

15
SalutonMondo

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
  }
}
15
Chau Thai

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.

10
Lalit Poptani

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.

5
user3316561

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;
    }
};
3
Arul Pandian

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.

2
AndroidDev

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

1
Popa Andrei

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

1
Gitesh Agarwal

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];
    }
}
1
Omer Leshem