Реализовать такую ​​функцию, как закрытие приложения iOS по вертикали Swipe-to-Dismiss с помощью ViewPager.

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

Чего бы мне хотелось, так это возможности вертикального свайпа на этих видах, их перевода по вертикали с помощью свайпа и затухания, а затем выполнения действия, когда они достигают определенного расстояния от края устройства.

Чтобы получить представление о том, о чем я думаю, в приложении «Галерея» вы можете сжать открытую фотографию, чтобы уменьшить масштаб и открыть горизонтальный вид кинопленки. Оттуда вы можете провести вверх (или вниз) по фото/видео, чтобы удалить его. Для тех, у кого нет такого же приложения Галерея, это точно так же, как закрытие приложений на iOS.

Я пробовал сканировать исходный код приложения «Галерея», но мне не удалось найти правильное действие.


person OneCricketeer    schedule 15.10.2015    source источник


Ответы (3)


view.setOnTouchListener(new View.OnTouchListener(){
    public boolean onTouch(View v, MotionEvent motion) {
       float y = motion.getY();
       /* NOTE: the following line might need to be in runOnUiThread() */
       view.animate().alpha(1-Math.abs(y-height/2)/(height/2)).setDuration(50).start();
       return true; //false if you want to pass this event on to other listeners
    }
});

Объяснение использования 1-Math.abs(y-height/2)/(height/2) заключается в том, что я хочу, чтобы альфа была равна 1, когда я нахожусь в центре, и альфа была равна 0, когда она находится вверху или внизу. Вы должны сами определить, как вы получаете значение height, или хотите ли вы использовать другой метод для вычисления альфы. Если вы хотите получить положение касания относительно экрана вместо положения относительно представления, используйте getRawY().

Кроме того, вам может быть полезно знать, что для того, чтобы увидеть, является ли MotionEvent событием нажатия, перетаскивания или отпускания, используйте motion.getAction() == с MotionEvent.ACTION_UP, MotionEvent.ACTION_MOVE и MotionEvent.ACTION_DOWN соответственно.

person geokavel    schedule 16.10.2015
comment
А если я хочу изменить положение в альфе, а не изменение продолжительности? Я хотел бы, чтобы представление исчезало либо по отношению к его исходному положению, либо по краю, к которому оно перемещается. - person OneCricketeer; 16.10.2015
comment
Обновлен код, чтобы отразить это. Больше не использует жесты. - person geokavel; 16.10.2015
comment
Хорошо, тогда как насчет перевода View в ViewPager, пока он исчезает? Похоже, этот код просто затухает вид в зависимости от положения касания. - person OneCricketeer; 16.10.2015
comment
Я раньше не делал того, что конкретно делаете вы, но, возможно, что-то подобное сработает view.setY(y). Возможно, это работает только с определенными макетами. - person geokavel; 16.10.2015

В итоге я добился того, что это работает более или менее, клонировав хорошо написанный Android-SwipeToDismiss библиотеку и просто заменив код ListView на ViewPager.

Готовое изделие выглядело так.

конечный результат

person OneCricketeer    schedule 30.03.2016
comment
Можете ли вы опубликовать свой код, который вы реализовали для viewpager? - person Krishna Meena; 23.04.2016
comment
Как я уже говорил в вопросе, сложно извлечь минимальный образец кода. Задействовано 5 классов и 2 интерфейса. Я предоставил ссылку на библиотеку, и изменить пример ListView для использования ViewPager просто (на мой взгляд) - person OneCricketeer; 23.04.2016
comment
То есть вы имеете в виду, что мне просто нужно заменить ListView на ViewPager, и это сработает? - person Krishna Meena; 24.04.2016
comment
Более или менее, да. Есть несколько разделов, которые необходимо изменить, чтобы использовать вертикальное смахивание вместо горизонтального. И я использовал ViewPager внутри фрагмента, который отображал страницы фрагментов, так что здесь началась сложность. - person OneCricketeer; 24.04.2016
comment
@KrishnaMeena ты добился в этом успеха? - person DjHacktorReborn; 07.10.2016

Проверьте приведенный ниже код, это может быть вам полезно:

    public class MainActivity extends Activity implements View.OnTouchListener{

    private RelativeLayout baseLayout;

    private int previousFingerPosition = 0;
    private int baseLayoutPosition = 0;
    private int defaultViewHeight;

    private boolean isClosing = false;
    private boolean isScrollingUp = false;
    private boolean isScrollingDown = false;

    @Override
    protected void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_popup);
        baseLayout = (RelativeLayout) findViewById(R.id.base_popup_layout);//this is the main layout
        baseLayout.setOnTouchListener(this);
    }


    public boolean onTouch(View view, MotionEvent event) {

        // Get finger position on screen
        final int Y = (int) event.getRawY();

        // Switch on motion event type
        switch (event.getAction() & MotionEvent.ACTION_MASK) {

            case MotionEvent.ACTION_DOWN:
                // save default base layout height
                defaultViewHeight = baseLayout.getHeight();

                // Init finger and view position
                previousFingerPosition = Y;
                baseLayoutPosition = (int) baseLayout.getY();
                break;

            case MotionEvent.ACTION_UP:
                // If user was doing a scroll up
                if(isScrollingUp){
                    // Reset baselayout position
                    baseLayout.setY(0);
                    // We are not in scrolling up mode anymore
                    isScrollingUp = false;
                }

                // If user was doing a scroll down
                if(isScrollingDown){
                    // Reset baselayout position
                    baseLayout.setY(0);
                    // Reset base layout size
                    baseLayout.getLayoutParams().height = defaultViewHeight;
                    baseLayout.requestLayout();
                    // We are not in scrolling down mode anymore
                    isScrollingDown = false;
                }
                break;
            case MotionEvent.ACTION_MOVE:
                if(!isClosing){
                    int currentYPosition = (int) baseLayout.getY();

                    // If we scroll up
                    if(previousFingerPosition >Y){
                        // First time android rise an event for "up" move
                        if(!isScrollingUp){
                            isScrollingUp = true;
                        }

                    // Has user scroll down before -> view is smaller than it's default size -> resize it instead of change it position
                    if(baseLayout.getHeight()<defaultViewHeight){
                        baseLayout.getLayoutParams().height = baseLayout.getHeight() - (Y - previousFingerPosition);
                        baseLayout.requestLayout();
                    }
                    else {
                        // Has user scroll enough to "auto close" popup ?
                        if ((baseLayoutPosition - currentYPosition) > defaultViewHeight / 4) {
                            closeUpAndDismissDialog(currentYPosition);
                            return true;
                        }

                        //
                    }
                    baseLayout.setY(baseLayout.getY() + (Y - previousFingerPosition));

                }
                // If we scroll down
                else{

                    // First time android rise an event for "down" move
                    if(!isScrollingDown){
                        isScrollingDown = true;
                    }

                    // Has user scroll enough to "auto close" popup ?
                    if (Math.abs(baseLayoutPosition - currentYPosition) > defaultViewHeight / 2)
                    {
                        closeDownAndDismissDialog(currentYPosition);
                        return true;
                    }

                    // Change base layout size and position (must change position because view anchor is top left corner)
                    baseLayout.setY(baseLayout.getY() + (Y - previousFingerPosition));
                    baseLayout.getLayoutParams().height = baseLayout.getHeight() - (Y - previousFingerPosition);
                    baseLayout.requestLayout();
                }

                // Update position
                previousFingerPosition = Y;
            }
            break;
        }
        return true;
    }
}

Для анимации используйте следующие методы:

   public void closeUpAndDismissDialog(int currentPosition){
    isClosing = true;
    ObjectAnimator positionAnimator = ObjectAnimator.ofFloat(baseLayout, "y", currentPosition, -baseLayout.getHeight());
    positionAnimator.setDuration(300);
    positionAnimator.addListener(new Animator.AnimatorListener()
    {
        . . .
        @Override
        public void onAnimationEnd(Animator animator)
        {
            finish();
        }
        . . .
    });
    positionAnimator.start();
}

public void closeDownAndDismissDialog(int currentPosition){
    isClosing = true;
    Display display = getWindowManager().getDefaultDisplay();
    Point size = new Point();
    display.getSize(size);
    int screenHeight = size.y;
    ObjectAnimator positionAnimator = ObjectAnimator.ofFloat(baseLayout, "y", currentPosition, screenHeight+baseLayout.getHeight());
    positionAnimator.setDuration(300);
    positionAnimator.addListener(new Animator.AnimatorListener()
     {
        . . .
        @Override
        public void onAnimationEnd(Animator animator)
        {
            finish();
        }
        . . .
    });
    positionAnimator.start();
}
person bhavesh N    schedule 17.11.2015
comment
Я предполагаю, что baseLayout может быть ViewPager вместо LinearLayout? Кроме того, имеет ли значение, если мой ViewPager, с которым я пытаюсь это сделать, находится внутри фрагмента? - person OneCricketeer; 17.11.2015
comment
baseLayout - это корневой родительский вид в вашем макете xml - person bhavesh N; 18.11.2015
comment
Я не хочу, чтобы вся активность перемещалась, а только один вид, отображаемый в настоящее время ViewPager. - person OneCricketeer; 18.11.2015
comment
Он работает с макетом, поэтому вы можете применить анимацию к макету, а в конце анимации просто все прошло. - person bhavesh N; 20.11.2015