swipelistview recyclerview library cardview android android-listview swipe-gesture

android - recyclerview - Deslizar el elemento ListView De derecha a izquierda mostrar el botón Eliminar



swipe recyclerview android (10)

Acabo de trabajar con el ViewSwitcher en 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>

En el ListAdapter: Implemente OnclickListeners para el botón Editar y Eliminar en el método getView (). El truco aquí es obtener la posición del ListItem dentro de los métodos onClick. Los métodos setTag () y getTag () se usan para esto.

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

En el Fragmento, agregue un Escucha de Gestos para detectar el Gesto Fling:

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

En el método onCreateView del Fragmento,

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

Esto funcionó para mí. Debería refinarlo más.

Tengo un ListView personalizado que muestra la lista de palabras que se seleccionan de la base de datos. Cuando deslizo este elemento de la lista, quiero mostrar el botón Eliminar como imagen a continuación. Y cuando presiono ese botón, se elimina de la base de datos y actualiza la vista de lista. metro

Ya miro en este código de ejemplo here . Pero todavía no funciona.


Defina un ViewPager en su diseño .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" />

Y luego, en su actividad / fragmento, configure un adaptador de pager personalizado:

En una actividad:

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

En un fragmento:

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

Crea nuestra clase de buscapersonas personalizada:

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



Es una pérdida de tiempo implementar desde cero esta funcionalidad. Implementé la biblioteca recomendada por SalutonMondo y estoy muy satisfecho. Es muy simple de usar y muy rápido. Mejoré la biblioteca original y agregué un nuevo oyente de clic para hacer clic en el elemento. También agregué la impresionante biblioteca de fuentes ( http://fortawesome.github.io/Font-Awesome/ ) y ahora puedes simplemente agregar un nuevo título de artículo y especificar el nombre del icono de la fuente.

Here está el enlace de Github


Hay una aplicación disponible que muestra una vista de lista que combina tanto deslizar para eliminar como arrastrar para reordenar elementos. El código se basa en el código de Chet Haase para deslizar-para-borrar y el código de Daniel Olshansky para arrastrar-reordenar.

El código de Chet borra un artículo inmediatamente. Mejoré esto haciendo que funcionara más como Gmail, donde el deslizamiento revela una vista inferior que indica que el elemento está eliminado pero proporciona un botón Deshacer, donde el usuario tiene la posibilidad de deshacer la eliminación. El código de Chet también tiene un error. Si tiene menos elementos en la vista de lista que el alto de la vista de lista y elimina el último, el último elemento parece no borrarse. Esto fue arreglado en mi código.

El código de Daniel requiere presionar largo en un elemento. Muchos usuarios encuentran esto poco intuitivo, ya que tiende a ser una función oculta. En cambio, modifiqué el código para permitir un botón "Mover". Simplemente presione el botón y arrastre el elemento. Esto está más en línea con la forma en que funciona la aplicación Google News cuando reordena los temas de noticias.

El código fuente junto con una aplicación de demostración está disponible en: https://github.com/JohannBlake/ListViewOrderAndSwipe

Chet y Daniel son ambos de Google.

El video de Chet sobre cómo eliminar elementos se puede ver en: https://www.youtube.com/watch?v=YCHNAi9kJI4

El video de Daniel sobre cómo reordenar los artículos se puede ver en: https://www.youtube.com/watch?v=_BZIvjMgH-Q

Se ha invertido una cantidad considerable de trabajo para unir todo esto para proporcionar una experiencia de interfaz de usuario parecida, por lo que agradecería un Voto igual o superior. Por favor, también protagonice el proyecto en Github.



He pasado por toneladas de bibliotecas de terceros para tratar de lograr esto. Pero ninguno de ellos muestra la fluidez y la experiencia de usabilidad que yo quería. Entonces decidí escribirlo yo mismo. Y el resultado fue, bueno, me encantó. Compartiré el código aquí. Tal vez lo escriba como una biblioteca que se puede incrustar en cualquier vista de reciclador en el futuro. Pero por ahora aquí está el código.

Nota: tengo uses la vista de reciclador y ViewHolder. Algunos valores están codificados, así que cámbielos de acuerdo a sus necesidades.

  • 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

    la clase pública ChatAdaptor extiende 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); } } }

¡¡Espero que esto ayude a alguien!!


Solía ​​tener el mismo problema para encontrar una buena biblioteca para hacer eso. Eventualmente, creé una biblioteca que puede hacer eso: SwipeRevealLayout

En archivo gradle:

dependencies { compile ''com.chauthai.swipereveallayout:swipe-reveal-layout:1.4.0'' }

En tu archivo 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>

Luego en su archivo de adaptador:

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


ver que el enlace fue muy agradable y simple. funciona bien ... no quieres que ninguna biblioteca funcione bien. haga clic 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; } };


Creé una demostración en mi github que incluye al deslizar de derecha a izquierda un botón Eliminar y luego puede eliminar su elemento de ListView y actualizar su ListView.