web-dev-qa-db-fra.com

Android ListView glisser à droite et à gauche pour accepter et rejeter

Je souhaite développer un affichage sous forme de liste qui, une fois balayée de gauche à droite - affiche dans le coin gauche une icône d'acceptation (vrai) (non cliquable - indique uniquement un changement de couleur lorsque vous balayez de gauche à droite), comme dans la capture d'écran suivante:

enter image description here

Lorsque je glisse de gauche à droite, il accepte (en appelant l'API "accept"), .__ et, lorsque je glisse de droite à gauche, le message suivant s'affiche:

enter image description here

Ceci est fait dans iOS, mais je ne trouve pas comment faire cela dans Android, j'ai essayé de googler mais je ne trouvais pas exactement ce que je voulais.

J'ai essayé l'exemple suivant: http://www.tutecentral.com/Android-swipe-listview/

mais dans cet exemple, lorsque je balaie de gauche à droite et de droite à gauche, la même méthode onOpened (..) est appelée. Il est donc déroutant de savoir quand appeler accept et quand appeler une API rejetée, car la même méthode est appelée pour tout type de glisser.

et je souhaite également que les images accept (du côté gauche) et rejetées (du côté droit) ne s'affichent que lorsque je balaie le curseur gauche-droite ou droite-gauche, mais lorsque je lève le doigt, elles doivent disparaître et l'ensemble de la liste doit être affiché. (ne jamais montrer les deux images en même temps).

Alors, aidez-moi à comprendre comment procéder.

Ma question est quelque peu déroutante mais je ne sais pas comment expliquer toute l'animation, alors j'ai essayé de l'expliquer comme ci-dessus.

Si quelqu'un peut m'aider, ce serait très apprécié.

11
Joseph Mekwan

Solution numéro 1:

Vous devez faire comme suit pour atteindre "près" de votre fonctionnalité,

Enveloppe l'adaptateur de votre ListView

Comme suit:

  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // Create an Adapter for your content
    String[] content = new String[20];
    for (int i=0;i<20;i++) content[i] = "Row "+(i+1);
    ArrayAdapter<String> stringAdapter = new ArrayAdapter<String>(
        this,
        R.layout.row_bg,
        R.id.text,
        new ArrayList<String>(Arrays.asList(content))
    );

   // Wrap your content in a SwipeActionAdapter
   mAdapter = new SwipeActionAdapter(stringAdapter);

   // Pass a reference of your ListView to the SwipeActionAdapter
   mAdapter.setListView(getListView());

   // Set the SwipeActionAdapter as the Adapter for your ListView
   setListAdapter(mAdapter);
  }

Créer une mise en page d'arrière-plan pour chaque direction de balayage

J'aime suivre:

  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

   // Create an Adapter for your content
   String[] content = new String[20];
   for (int i=0;i<20;i++) content[i] = "Row "+(i+1);
   ArrayAdapter<String> stringAdapter = new ArrayAdapter<String>(
        this,
        R.layout.row_bg,
        R.id.text,
        new ArrayList<String>(Arrays.asList(content))
   );

   // Wrap your content in a SwipeActionAdapter
   mAdapter = new SwipeActionAdapter(stringAdapter);

   // Pass a reference of your ListView to the SwipeActionAdapter
   mAdapter.setListView(getListView());

   // Set the SwipeActionAdapter as the Adapter for your ListView
   setListAdapter(mAdapter);

   // Set backgrounds for the swipe directions
    mAdapter.addBackground(SwipeDirections.DIRECTION_FAR_LEFT,R.layout.row_bg_left_far)
          .addBackground(SwipeDirections.DIRECTION_NORMAL_LEFT,R.layout.row_bg_left)
         .addBackground(SwipeDirections.DIRECTION_FAR_RIGHT,R.layout.row_bg_right_far)
        .addBackground(SwipeDirections.DIRECTION_NORMAL_RIGHT,R.layout.row_bg_right);
}

Vous avez les deux bibliothèques et exemple de ici: https://github.com/wdullaer/SwipeActionAdapter

Cela n’exécutera pas exactement ce que vous voulez, mais j’espère que cela vous aidera beaucoup à remplir vos fonctions.

Solution numéro 2: 

La solution 2 concerne le changement de code dans votre code utilisé: http://www.tutecentral.com/Android-swipe-listview/ 

j'avais essayé ton code depuis le lien http://www.tutecentral.com/Android-swipe-listview/ et en changeant un peu de code pour résoudre avec succès ton problème (ta confusion) à propos de la méthode onOpened (..) (appelée de gauche à droite et vice versa) 

Premier changement: 

  1. le fichier de disposition custom_row.xml comporte trois boutons swipe_button1 à 3, remove au milieu d’eux.

  2. Copier coller le code suivant pour rester deux boutons:

    <Button
        Android:id="@+id/swipe_button1"
        Android:layout_width="48dp"
        Android:layout_height="48dp"
        Android:layout_alignParentLeft="true"
        Android:layout_alignParentTop="true"
        Android:background="@drawable/your_accept_image" />
    
    <Button
        Android:id="@+id/swipe_button3"
        style="@style/MyListButtonAction"
        Android:layout_width="48dp"
        Android:layout_height="48dp"
        Android:layout_alignParentRight="true"
        Android:layout_alignParentTop="true"
        Android:background="@drawable/your_reject_image" />
    

Reste le même code pour cette mise en page.

Deuxième changement:

Alors maintenant, votre code d’acceptation et de rejet et le code de liste sont prêts, discutez maintenant de la méthode onOpened (..).

Solution de confusion 1 - Vous avez dit, votre méthode onOpend (...) a appelé la même chose de gauche à droite et vice-verset 

-> juste pour changer suivant:

public void onOpened(int position, boolean toRight) {

            if(toRight)
            {

                //  for left to right your api calling here
                swipelistview.closeAnimate(position);
            }
            else
            {
                // for right to left your api calling here
                swipelistview.closeAnimate(position);
            }


        }

Solution de confusion 2 quand je prends le doigt vers le haut, il doit afficher tout le listview ou les côtés de listview doivent le conserver dans les coins pour que cela ne fonctionne pas 

-> je l'ai déjà répondu ci-dessus

appelé swipelistview.closeAnimate (position); dans les deux cas sinon, il masque à gauche l'acceptation et à droite l'image de rejeter lorsque vous faites glisser votre doigt vers la gauche et la droite.

Le code final est donc le suivant:

Disposition complète de cutom_row.xml 

 <?xml version="1.0" encoding="utf-8"?>
 <FrameLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
     Android:layout_width="fill_parent"
     Android:layout_height="fill_parent" >

  <RelativeLayout
    Android:id="@+id/back"
    Android:layout_width="match_parent"
    Android:layout_height="wrap_content"
    Android:tag="back" >

    <Button
        Android:id="@+id/swipe_button1"
        Android:layout_width="48dp"
        Android:layout_height="48dp"
        Android:layout_alignParentLeft="true"
        Android:layout_alignParentTop="true"
        Android:background="@drawable/accept_image" />

    <Button
        Android:id="@+id/swipe_button3"
        style="@style/MyListButtonAction"
        Android:layout_width="48dp"
        Android:layout_height="48dp"
        Android:layout_alignParentRight="true"
        Android:layout_alignParentTop="true"
        Android:background="@drawable/reject_image" />
</RelativeLayout>


<RelativeLayout
    Android:id="@+id/front"
    style="@style/MyListFrontContent"
    Android:orientation="vertical"
    Android:tag="front" >

    <ImageView
        Android:id="@+id/example_image"
        style="@style/MyListImage" />

    <TextView
        Android:id="@+id/example_itemname"
        style="@style/MyListTitle"
        Android:layout_width="fill_parent"
        Android:layout_height="wrap_content"
        Android:layout_toRightOf="@id/example_image" />
  </RelativeLayout>

</FrameLayout>

Ensemble MainActivity.Java

public class MainActivity extends Activity {

SwipeListView swipelistview;
ItemAdapter adapter;
List<ItemRow> itemData;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    swipelistview=(SwipeListView)findViewById(R.id.example_swipe_lv_list); 
    itemData=new ArrayList<ItemRow>();
    adapter=new ItemAdapter(this,R.layout.custom_row,itemData);

    swipelistview.setSwipeListViewListener(new BaseSwipeListViewListener() {
        @Override
        public void onOpened(int position, boolean toRight) {

            if(toRight)
            {

                //  for left to right your api calling here
                swipelistview.closeAnimate(position);
            }
            else
            {
                // for right to left your api calling here
                swipelistview.closeAnimate(position);
            }


        }

        @Override
        public void onClosed(int position, boolean fromRight) {
            // close list slide
        }

        @Override
        public void onListChanged() {

        }

        @Override
        public void onMove(int position, float x) {


        }

        @Override
        public void onStartOpen(int position, int action, boolean right) {
            Log.d("swipe", String.format("onStartOpen %d - action %d", position, action));



        }

        @Override
        public void onStartClose(int position, boolean right) {
            Log.d("swipe", String.format("onStartClose %d", position));


        }

        @Override
        public void onClickFrontView(int position) {
            Log.d("swipe", String.format("onClickFrontView %d", position));




        }

        @Override
        public void onClickBackView(int position) {
            Log.d("swipe", String.format("onClickBackView %d", position));

            swipelistview.closeAnimate(position);//when you touch back view it will close

        }

        @Override
        public void onDismiss(int[] reverseSortedPositions) {

        }

    });

    //These are the swipe listview settings. you can change these
    //setting as your requirement 
    swipelistview.setSwipeMode(SwipeListView.SWIPE_MODE_BOTH); // there are five swiping modes
    //    swipelistview.setSwipeActionLeft(SwipeListView.SWIPE_ACTION_DISMISS); //there are four swipe actions 
    swipelistview.setSwipeActionRight(SwipeListView.SWIPE_ACTION_REVEAL);
    swipelistview.setOffsetLeft(convertDpToPixel(0f)); // left side offset
    swipelistview.setOffsetRight(convertDpToPixel(80f)); // right side offset
    swipelistview.setAnimationTime(500); // Animation time
    swipelistview.setSwipeOpenOnLongPress(true); // enable or disable SwipeOpenOnLongPress

    swipelistview.setAdapter(adapter);


    for(int i=0;i<10;i++)
    {
        itemData.add(new ItemRow("Swipe Item"+ i,getResources().getDrawable(R.drawable.ic_launcher) ));

    }

    adapter.notifyDataSetChanged();
}

public int convertDpToPixel(float dp) {
    DisplayMetrics metrics = getResources().getDisplayMetrics();
    float px = dp * (metrics.densityDpi / 160f);
    return (int) px;
}


@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menu);
    return true;
  }

 }

Les autres codes et bibliothèques restent les mêmes, Cela vous sera utile, à vous aussi, alors profitez-en.

13
Nirav Mehta

Cela a fonctionné pour moi ... j'espère que cela fonctionnera pour vous ..!

définir OnTouchListener sur listview en tant que 

listview.setOnTouchListener(new OnSwipeTouchListener(getActivity(),
            listview));

La classe OnSwipeTouchListener est la suivante:

public class OnSwipeTouchListener implements OnTouchListener {

    ListView list;
    private GestureDetector gestureDetector;
    private Context context;

    public OnSwipeTouchListener(Context ctx, ListView list) {
        gestureDetector = new GestureDetector(ctx, new GestureListener());
        context = ctx;
        this.list = list;
    }

    public OnSwipeTouchListener() {
        super();
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        return gestureDetector.onTouchEvent(event);
    }

    public void onSwipeRight(int pos) {
        //Do what you want after swiping left to right

    }

    public void onSwipeLeft(int pos) {

        //Do what you want after swiping right to left
    }

    private final class GestureListener extends SimpleOnGestureListener {

        private static final int SWIPE_THRESHOLD = 100;
        private static final int SWIPE_VELOCITY_THRESHOLD = 100;

        @Override
        public boolean onDown(MotionEvent e) {
            return true;
        }

        private int getPostion(MotionEvent e1) {
            return list.pointToPosition((int) e1.getX(), (int) e1.getY());
        }

        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2,
                float velocityX, float velocityY) {
            float distanceX = e2.getX() - e1.getX();
            float distanceY = e2.getY() - e1.getY();
            if (Math.abs(distanceX) > Math.abs(distanceY)
                    && Math.abs(distanceX) > SWIPE_THRESHOLD
                    && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
                if (distanceX > 0)
                    onSwipeRight(getPostion(e1));
                else
                    onSwipeLeft(getPostion(e1));
                return true;
            }
            return false;
        }

    }
}
5
Pratibha Sarode

S'il vous plaît éviter l'approche ci-dessus, sinon vous allez à plein contrôleur avec la logique de vue (quelque chose que vous devez éviter) visitez https://github.com/xenione/SwipeLayout

1
Xenione

basée sur la solution @Pratibha Sarode, je l’adapte comme suit avec une listview poupulée avec un curseuradaptor et une base de données: Dans l’activité principale:

  //-- Attach cursor adapter to the ListView
    lvItems.setAdapter(todoAdapter);
    /////////////////// Swipe Management
    lvItems.setOnTouchListener(new OnSwipeList(AfficList.this,lvItems){
        public void onSwipeRight(int pos) {
            AnnonceDbHandler dbHandler = new AnnonceDbHandler(AfficList.this, null, null, 1);
            String sIdAnn=dbHandler.RechercheIdIndex(pos);
            //Toast.makeText(AfficList.this, "Right ("+pos+") : "+sIdAnn, Toast.LENGTH_SHORT).show();
            dbHandler.deleteAnnonce(sIdAnn, AfficList.this);
            Cursor NewCursor = dbAnnonces.rawQuery("SELECT  * FROM annonces", null);
            todoAdapter.swapCursor(NewCursor);
            lvItems.setAdapter(todoAdapter);
            todoAdapter.notifyDataSetChanged();
        }
        public void onSwipeLeft(int pos) {
            AnnonceDbHandler dbHandler = new AnnonceDbHandler(AfficList.this, null, null, 1);
            String sIdAnn=dbHandler.RechercheIdIndex(pos);
            //Toast.makeText(AfficList.this, "Right ("+pos+") : "+sIdAnn, Toast.LENGTH_SHORT).show();
            dbHandler.deleteAnnonce(sIdAnn, AfficList.this);
            Cursor NewCursor = dbAnnonces.rawQuery("SELECT  * FROM annonces", null);
            todoAdapter.swapCursor(NewCursor);
            lvItems.setAdapter(todoAdapter);
            todoAdapter.notifyDataSetChanged();
        }
    });

Cela fonctionne très bien de supprimer des lignes avec le déplacement par glissement!

1
AndroLogiciels

Jetez un oeil à this library, cela vous donnera de très bons exemples et vous indiquera la bonne direction. Bonne chance.

1
EE66

Utiliser une réponse sur https://stackoverflow.com/a/31094315/2914140 Je l’ai fait.

View.OnTouchListener swipeListener = new View.OnTouchListener() {
    private float dx;

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                dx = v.getX() - event.getRawX();
                break;
            case MotionEvent.ACTION_MOVE:
                // You can limit x-coordinate.
                float x = Math.min(event.getRawX() + dx, 0);
                // x = Math.max(x, ((View) v.getParent()).getWidth() - v.getWidth()); // Scroll if layout is wider than screen.
                v.animate()
                        .x(x)
                        .setDuration(0)
                        .start();
                break;
            default:
                return false;
        }
        return true;
    }
};

Dans getView de votre adaptateur, écrivez:

@Override
public View getView(final int position, View convertView, ViewGroup parent) {
    final ViewHolder viewHolder;
    if (convertView == null) {
        convertView = inflater.inflate(R.layout.item_layout, false);
        viewHolder = new ViewHolder(convertView);
        convertView.setTag(viewHolder);
    } else {
        viewHolder = (ViewHolder) convertView.getTag();
    }

    // Fill data.
    final Item item = items.get(position);
    viewHolder.caption.setText(item.getCaption());
    // Set onTouch listener.
    convertView.setOnTouchListener(swipeListener);
    return convertView;
}

Je pense que la même chose peut être obtenue en utilisant HorizontalScrollView dans item_layout.xml.

0
CoolMind