Android new Inbox app style listview with swipe left and right

m trying to build android new inbox style listview with swipe left and right as shown in this image , i have tried 47deg swipelistview but its not that stable , is there any other library available?!

right swipe
left swipe

  • Comparison between Corona, Phonegap, Titanium
  • Error Occurs while Running Android Project - Unsupported major.minor version
  • play_licensing throws AIDL error with downloader_library for APK Expansion with Gradle
  • TextView.setText (Android) is causing crashes.. any idea why?
  • Android RelativeLayout Selector state_pressed doesn't work
  • Android : Capture a document & Scan it using camera
  • Tried so far with 47 deg

     public class MainActivity extends Activity {
    
            Listview pullToRefreshListView;
            SwipeListView swipelistview;
            ItemAdapter adapter;
            List<ItemRow> itemData;
    
            @Override
            protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.activity_main);
    
                pullToRefreshListView = (ListView) findViewById(R.id.example_swipe_lv_list);
                swipelistview = pullToRefreshListView.getRefreshableView();
                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) {
                            adapter.remove(position);
                            Toast.makeText(MainActivity.this, "Open to dismiss",
                                    Toast.LENGTH_SHORT).show();
                        } // swipelistview.dismiss(position);
                        else {
                            Toast.makeText(MainActivity.this, "Open to edit",
                                    Toast.LENGTH_SHORT).show();
                        }
                    }
    
                    @Override
                    public void onClosed(int position, boolean fromRight) {
                    }
    
                    @Override
                    public void onListChanged() {
                    }
    
                    @Override
                    public void onMove(int position, float x) {
                    }
    
                    @Override
                    public void onStartOpen(int position, int action, boolean right) {
                        if (right) {
                            // adapter.onRight();
                            swipelistview.getChildAt(position).findViewById(R.id.back)
                                    .setBackgroundColor(Color.GREEN);
    
                            swipelistview.getChildAt(position)
                                    .findViewById(R.id.imageViewLeft)
                                    .setVisibility(View.VISIBLE);
                            swipelistview.getChildAt(position)
                                    .findViewById(R.id.imageViewRight)
                                    .setVisibility(View.GONE);
                        } else {
                            // adapter.onLeft();
                            swipelistview.getChildAt(position).findViewById(R.id.back)
                                    .setBackgroundColor(Color.RED);
                            swipelistview.getChildAt(position)
                                    .findViewById(R.id.imageViewLeft)
                                    .setVisibility(View.GONE);
                            swipelistview.getChildAt(position)
                                    .findViewById(R.id.imageViewRight)
                                    .setVisibility(View.VISIBLE);
                        }
                    }
    
                    @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));
    
                        // swipelistview.openAnimate(position); //when you touch front
                        // view it will open
    
                    }
    
                    @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.setSwipeActionRight(SwipeListView.SWIPE_ACTION_REVEAL); // there
                                                                                        // are
                                                                                        // four
                                                                                        // swipe
                                                                                        // actions
                swipelistview.setSwipeActionLeft(SwipeListView.SWIPE_ACTION_REVEAL);
                swipelistview.setOffsetRight(convertDpToPixel(0f)); // left side
                                                                    // offset
                swipelistview.setOffsetLeft(convertDpToPixel(0f)); // right side
                                                                    // offset
                swipelistview.setAnimationTime(60); // Animation time
                swipelistview.setSwipeOpenOnLongPress(false); // enable or disable
                                                                // SwipeOpenOnLongPress
                swipelistview.setSwipeCloseAllItemsWhenMoveList(true);
                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;
    }
        }
    

    Adapter class

    public class ItemAdapter extends ArrayAdapter<ItemRow> {
    
        List<ItemRow> data;
        Context context;
        int layoutResID;
    
        public ItemAdapter(Context context, int layoutResourceId, List<ItemRow> data) {
            super(context, layoutResourceId, data);
    
            this.data = data;
            this.context = context;
            this.layoutResID = layoutResourceId;
    
            // TODO Auto-generated constructor stub
        }
    
        NewsHolder holder = null;
        View row = null;
    
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
    
            row = convertView;
            holder = null;
    
            if (row == null) {
                LayoutInflater inflater = ((Activity) context).getLayoutInflater();
                row = inflater.inflate(layoutResID, parent, false);
    
                holder = new NewsHolder();
    
                holder.itemName = (TextView) row
                        .findViewById(R.id.example_itemname);
                holder.icon = (ImageView) row.findViewById(R.id.example_image);
                holder.imageViewRight = (ImageView) row
                        .findViewById(R.id.imageViewRight);
                holder.imageViewLeft = (ImageView) row
                        .findViewById(R.id.imageViewLeft);
    
                row.setTag(holder);
            } else {
                holder = (NewsHolder) row.getTag();
            }
    
            ItemRow itemdata = data.get(position);
            holder.itemName.setText(itemdata.getItemName());
            holder.icon.setImageDrawable(itemdata.getIcon());
    
            return row;
    
        }
        public void remove(int pos){
            data.remove(pos);
    
        }
    
        public void onLeft() {
    
            holder.imageViewLeft.setVisibility(View.VISIBLE);
            holder.imageViewRight.setVisibility(View.GONE);
        }
    
        public void onRight() {
            holder.imageViewRight.setVisibility(View.VISIBLE);
            holder.imageViewLeft.setVisibility(View.GONE);
        }
    
        static class NewsHolder {
    
            TextView itemName;
            ImageView icon;
            ImageView imageViewLeft, imageViewRight;
    
            RelativeLayout mRelativeLayout;
        }
    

    Related posts:

    Paint bordered text in a Canvas android
    Sharedpreference byte value cleared after app killed via &#039;Force Stop&#039; or task mana...
    Custom font for webview
    Smooth scroll and Fling with NestedScrollView,AppBarLayout and CoordinatorLayout
    Night mode for Google maps?
    Why does setImageBitmap has no effect on custom ImageButton?
  • “Service MeasurementBrokerService is in use” is showing in my application process
  • Android AlarmManager - RTC_WAKEUP vs ELAPSED_REALTIME_WAKEUP
  • Unable to scroll AppBarLayout and collapsing toolbar with NestedScrollView smoothly
  • Android: content observer's “onChange()” method is called multiple times
  • Run custom ROM on Android Emulator
  • Change Line Color of EditText - Android
  • 3 Solutions collect form web for “Android new Inbox app style listview with swipe left and right”

    Check out: SwipeActionAdapter

    It’s a great library that does exactly what you’re asking for. It allows Swipe in both directions with an underlying Layout or Color. It’s easy to implement and looks nice!

    Left Swipe
    Right Swipe

    Instead of using a custom ListView you can simply support “swipe” gesture on list items onTouch, like the following:

    private static final int DEFAULT_THRESHOLD = 128;
    
    row.setOnTouchListener(new View.OnTouchListener() {
    
        int initialX = 0;
        final float slop = ViewConfiguration.get(context).getScaledTouchSlop();
    
        public boolean onTouch(final View view, MotionEvent event) {
            if (event.getAction() == MotionEvent.ACTION_DOWN) {
                initialX = (int) event.getX();
                view.setPadding(0, 0, 0, 0);
            } else if (event.getAction() == MotionEvent.ACTION_MOVE) {
                int currentX = (int) event.getX();
                int offset = currentX - initialX;
                if (Math.abs(offset) > slop) {
                    view.setPadding(offset, 0, 0, 0);
    
                    if (offset > DEFAULT_THRESHOLD) {
                        // TODO :: Do Right to Left action! And do nothing on action_up.
                    } else if (offset < -DEFAULT_THRESHOLD) {
                        // TODO :: Do Left to Right action! And do nothing on action_up.
                    }
                }
            } else if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL) {
                // Animate back if no action was performed.
                ValueAnimator animator = ValueAnimator.ofInt(view.getPaddingLeft(), 0);
                animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                    @Override
                    public void onAnimationUpdate(ValueAnimator valueAnimator) {
                        view.setPadding((Integer) valueAnimator.getAnimatedValue(), 0, 0, 0);
                    }
                });
                animator.setDuration(150);
                animator.start();
            }
    };
    

    I also use reverse animation if no action was performed.

    This solution is lightweight so you should not experience any lags.

    Updated Answer

    As I mentioned previously, I took the same approach and it seems to work as expected. I have added 3 layers to a RelativeLayout. Top layer is what you want to show. Second layer is a plain background with delete icon at the left. Third layer is another plain background with share icon at the right. I implemented a swipe detector class which extends View.OnTouchListener.

    public class SwipeDetector implements View.OnTouchListener {
    
        private static final int MIN_DISTANCE = 300;
        private static final int MIN_LOCK_DISTANCE = 30; // disallow motion intercept
        private boolean motionInterceptDisallowed = false;
        private float downX, upX;
        private ObjectHolder holder;
        private int position;
    
        public SwipeDetector(ObjectHolder h, int pos) {
            holder = h;
            position = pos;
        }
    
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN: {
                downX = event.getX();
                return true; // allow other events like Click to be processed
            }
    
            case MotionEvent.ACTION_MOVE: {
                upX = event.getX();
                float deltaX = downX - upX;
    
                if (Math.abs(deltaX) > MIN_LOCK_DISTANCE && listView != null && !motionInterceptDisallowed) {
                    listView.requestDisallowInterceptTouchEvent(true);
                    motionInterceptDisallowed = true;
                }
    
                if (deltaX > 0) {
                    holder.deleteView.setVisibility(View.GONE);
                } else {
                    // if first swiped left and then swiped right
                    holder.deleteView.setVisibility(View.VISIBLE);
                }
    
                swipe(-(int) deltaX);
                return true;
            }
    
            case MotionEvent.ACTION_UP:
                upX = event.getX();
                float deltaX = upX - downX;
                if (Math.abs(deltaX) > MIN_DISTANCE) {
                    // left or right
                    swipeRemove();
                } else {
                    swipe(0);
                }
    
                if (listView != null) {
                    listView.requestDisallowInterceptTouchEvent(false);
                    motionInterceptDisallowed = false;
                }
    
                holder.deleteView.setVisibility(View.VISIBLE);
                return true;
    
            case MotionEvent.ACTION_CANCEL:
                holder.deleteView.setVisibility(View.VISIBLE);
                return false;
            }
    
        return true;
        }
    
        private void swipe(int distance) {
            View animationView = holder.mainView;
            RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) animationView.getLayoutParams();
            params.rightMargin = -distance;
            params.leftMargin = distance;
            animationView.setLayoutParams(params);
        }
    
        private void swipeRemove() {
            remove(getItem(position));
            notifyDataSetChanged();
        }
    }
    

    public static class ObjectHolder {
        public LinearLayout mainView;
        public RelativeLayout deleteView;
        public RelativeLayout shareView;
    
        /* other views here */
    }
    

    I have also added requestDisallowInterceptTouchEvent so that ListView (which is parent) doesn’t intercept the touch event when there’s some amount of vertical scrolling involved.

    I have written a blogpost about it which you can find it here. I have also added a Youtube video for demo.


    Old Answer

    I implemented one of these myself, but it’s a bit different. I use just touch instead of swiping. Touch to open, touch to close. Here’s youtube demo.

    I created custom ArrayAdapter. To set the layout, I created a custom layout like this.

    <RelativeLayout>
         <RelativeLayout>
              <Stuff that you want at the back of your list/>
         </RelativeLayout>
         <RelativeLayout>
              <Stuff that you want at the front of your list/>
         </RelativeLayout>
    </RelativeLayout>
    

    Using RelativeLayout, I am putting the top view over the bottom view. Both have same sizes. You can use different layouts for inner layouts.

    In Custom ArrayAdapter,

    @Override
    public view getView(int position, View convertView, ViewGroup parent) {
        // get holder and entry
        // set each element based on entry preferences
    
    
    
        holder.topView.setOnClickListener(new View.OnClickListener() {
    
              @Override
              public void onClick(View v) {
                  if (entry.isSwiped()) {
                      swipeWithAnimationValue(holder.topView, 1);
                      entry.setSwiped(false);
                  } else {
                      closeOtherSwipes(entry);  // if you want to keep only one entry open at a time
                      swipeWithAnimationValue(holder.topView, 0);
                      entry.setSwiped(true);
                  }
             }
       });
    }
    

    Normal Animation would not work as it just shifts the view, but it’s still there so if you try to click, the click still occurs on the top view. Hence I have used valueAnimator and actually shifted those lists.

    public void swipeWithAnimationValue(final View view, final int direction) {
        final int width = view.getWidth();
        Log.i(TAG, "view width = " + String.valueOf(width));
        ValueAnimator animationSwipe;
        int duration = 300;
        if (direction == 0) {
             animationSwipe = ValueAnimator.ofInt(0, view.getWidth() - 200);
        } else {
             animationSwipe = ValueAnimator.ofInt(view.getWidth() - 200, 0);
        }
    
        animationSwipe.setDuration(duration);
        AnimatorUpdateListener maringUpdater = new AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
    
                 RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) view.getLayoutParams();
                 params.rightMargin = -(Integer)animation.getAnimatedValue();
                 params.leftMargin = (Integer)animation.getAnimatedValue();
                 view.setLayoutParams(params);
            }
        };
    
        animationSwipe.addUpdateListener(maringUpdater);
        animationSwipe.setRepeatCount(0);
        animationSwipe.start();
    }
    
    Android Babe is a Google Android Fan, All about Android Phones, Android Wear, Android Dev and Android Games Apps and so on.