Новый список приложений в стиле «Входящие» для Android с прорисовкой влево и вправо

M пытается создать андроид в новом списке в стиле «Входящие» с прокруткой влево и вправо, как показано на этом изображении, я пробовал swipelistview 47deg, но его не так стабильно, есть ли какая-либо другая библиотека?

Правый салфетки Левый салфетки

Пробовал до сих пор с 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; } 

Solutions Collecting From Web of "Новый список приложений в стиле «Входящие» для Android с прорисовкой влево и вправо"

Проверьте: SwipeActionAdapter

Это отличная библиотека, которая делает именно то, о чем вы просите. Он позволяет прокручивать в обоих направлениях с помощью Layout или Color . Это легко реализовать и выглядит красиво!

Левая стрелка Справа

Вместо использования настраиваемого 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(); } }; 

Я также использую обратную анимацию, если никаких действий не было выполнено.

Это решение является легким, поэтому вы не должны испытывать никаких задержек.

Обновленный ответ

Как я упоминал ранее, я придерживался того же подхода и, похоже, работает так, как ожидалось. Я добавил 3 слоя в RelativeLayout. Верхний слой – это то, что вы хотите показать. Второй слой – это простой фон с иконкой удаления слева. Третий слой – это еще один простой фон с иконкой с изображением справа. Я View.OnTouchListener класс детектирования swipe, который расширяет 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 (родительский) не перехватывал событие касания, когда задействовано некоторое количество вертикальной прокрутки.

Я написал блог-блог об этом, который вы можете найти здесь . Я также добавил видео Youtube для демонстрации .


Старый ответ

Я реализовал один из них сам, но он немного другой. Я использую только прикосновение, а не прокручивание. Нажмите, чтобы открыть, коснитесь, чтобы закрыть. Вот демоверсия youtube .

Я создал пользовательский ArrayAdapter. Чтобы установить макет, я создал собственный макет, подобный этому.

 <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 , я помещаю верхний вид в нижний вид. Оба имеют одинаковые размеры. Вы можете использовать разные макеты для внутренних макетов.

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

Обычная анимация не будет работать, поскольку она просто сдвигает представление, но она все еще там, поэтому, если вы пытаетесь щелкнуть, щелчок по-прежнему появляется на верхнем уровне. Следовательно, я использовал 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(); }