Android新的收件箱应用程序样式列表视图左右滑动

M试图构buildAndroid新的收件箱风格列表视图左右滑动如本图所示,我已经尝试47deg swipelistview,但它不是那么稳定,是否有任何其他库可用?!

正确的滑动 左滑动

目前尝试47度

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

适配器类

 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 of "Android新的收件箱应用程序样式列表视图左右滑动"

签出: SwipeActionAdapter

这是一个伟大的图书馆,正是你所要求的。 它允许在底层LayoutColor 两个方向滑动 。 这很容易实现,看起来不错!

左滑动 右滑动

而不是使用自定义的ListView,你可以简单地支持在列表项onTouch上的“滑动”手势,如下所示:

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

如果不执行任何操作,我也使用反向animation。

这个解决scheme是轻量级的,所以你不应该经历任何滞后。

更新的答案

正如我前面提到的,我采取了同样的方法,似乎按预期工作。 我已经添加了3层到一个RelativeLayout。 顶层是你想要显示的。 第二层是一个带有删除图标的简单背景。 第三层是另一个带有共享图标的简单背景。 我实现了一个扩展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 */ } 

我还添加了requestDisallowInterceptTouchEvent以便在涉及到一定数量的垂直滚动时,ListView(它是父级)不会拦截触摸事件。

我写了一篇关于它的博客文章,你可以在这里find它。 我还添加了一个Youtubevideo演示 。


老答案

我自己实现了其中一个,但是有点不同。 我只是用触摸而不是滑动。 触摸打开,触摸closures。 这里是YouTube演示 。

我创build了自定义ArrayAdapter。 为了设置布局,我创build了一个像这样的自定义布局。

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

使用RelativeLayout ,我把顶视图放在底部视图上。 两者都有相同的大小。 您可以对内部布局使用不同的布局。

在自定义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); } } }); } 

普通animation不能正常工作,因为它只是移动视图,但它仍然存在,所以如果您尝试点击,点击仍然出现在顶视图。 因此,我使用了valueAnimator,并实际移动了这些列表。

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