fragments - handle swipe android




Проведите назад, как Pinterest или Tumblr (6)

Кто-нибудь имеет представление о том, как Pinterest или Tumblr внедрили там метод «проведите назад».

т.е. на Pinterest вы можете нажать на сообщение в ленте новостей. Затем DetailActivity и отображает детали для выбранного сообщения. Затем вы можете нажать кнопку «Назад», чтобы вернуться к активности ленты новостей, или вы можете прокручивать (активность данных) влево, чтобы вернуться к активности ленты новостей.

Видео: http://youtu.be/eVcSCWetnTA

Обычно я бы использовал overridePendingTransition() , но overridePendingTransition() принимает анимацию ( R.anim.foo ресурсов, такие как R.anim.foo ). Pinterest и Tumblr запускают анимацию только в том случае, если пользователь выполняет жестовые салфетки. Они также поддерживают некоторую «анимацию кадра за кадром» в соответствии с движением пальцев. Таким образом, они отслеживают расстояние перемещения пальца и оживляют переход к соответствующему процентному значению.

Я знаю, как использовать «реальный java» Animation / AnimatorSet Object с FragmentTransaction для анимации замены фрагмента. С фрагментами я должен переопределить onCreateAnimator() , но я не знаю, как реализовать что-то подобное с Activity. Есть ли onCreateAnimator() (или что-то подобное) для onCreateAnimator() ? Также не уверен, как прокручивать поведение, так как он не запускает анимацию прямо сейчас, но больше пошаговое изменение свойств окна / Activity / Fragment или что-то еще ...

Какие-либо предложения?

EDIT: Я нашел видео приложения pinterest на youtube: http://youtu.be/eVcSCWetnTA То, что я хочу реализовать.

Я предполагаю, что Pinterest работает с Fragments и onCreateAnimator() чтобы добиться «прокрутки назад». Поскольку у моего приложения уже есть Фрагмент и ChildFragments в деятельности, мне было бы намного легче, если бы я мог реализовать это для Деяний.

Еще раз: я знаю, как распознавать жесты пальцев, и это не то, о чем я прошу. Смотрите видео на YouTube: http://youtu.be/eVcSCWetnTA

UPDATE: я создал небольшую библиотеку, которая не имеет точно такого же поведения, как реализация Pinterest или Tumblrs, однако для моих приложений это кажется мне хорошим решением: https://github.com/sockeqwe/SwipeBack?source=c


Кажется, что эффект, который вы ищете, является одним из образцов для ViewPager на веб-сайте разработчика Android.

Посмотрите http://developer.android.com/training/animation/screen-slide.html#depth-page , в разделе Трансформатор страницы глубины . Он имеет видео и исходный код.

Используя ViewPager.PageTransformer вы можете решить, как ведут себя страницы при переключении с одного на другой.

Единственное различие между образцом и видео, с которым вы связаны, заключается в том, что левое право кажется перевернутым, но должно быть хорошей отправной точкой для того, что я видел на http://youtu.be/eVcSCWetnTA связанного с вопросом. Действия по двум точкам должны быть заменены. Как показано в этом фрагменте кода (1-й параметр для mPager.setPageTransformer должен быть reverseDrawingOrder = false). Обратите внимание на среднюю 2, if разделы разделены, а переменная position обрабатывается немного по-разному для сторон переключения. Бодчий эффект остается как упражнение. Пожалуйста, поделитесь, когда получите это!

    package com.example.android.animationsdemo;

    import android.support.v4.view.ViewPager;
    import android.view.View;

    public class SinkPageTransformer implements ViewPager.PageTransformer {
            private static float MIN_SCALE = 0.75f;

            public void transformPage(View view, float position) {
                    int pageWidth = view.getWidth();

                    if (position < -1) { // [-Infinity,-1)
                            // This page is way off-screen to the left.
                            view.setAlpha(0);

                    } else if (position <= 0) { // [-1,0]
                            // Fade the page out.
                            view.setAlpha(1 + position);

                            // Counteract the default slide transition
                            view.setTranslationX(pageWidth * -position);

                            // Scale the page down (between MIN_SCALE and 1)
                            float scaleFactor = MIN_SCALE
                                            + (1 - MIN_SCALE) * (1 - Math.abs(position));
                            view.setScaleX(scaleFactor);
                            view.setScaleY(scaleFactor);

                    } else if (position <= 1) { // (0,1]
                            // Use the default slide transition when moving to the left page
                            view.setAlpha(1);
                            view.setTranslationX(0);
                            view.setScaleX(1);
                            view.setScaleY(1);

                    } else { // (1,+Infinity]
                            // This page is way off-screen to the right.
                            view.setAlpha(0);
                    }
            }
    }

И на всякий случай, когда страница с образцом идет пуфом, вот оригинальный код этого раздела:

    public class DepthPageTransformer implements ViewPager.PageTransformer {
        private static float MIN_SCALE = 0.75f;

        public void transformPage(View view, float position) {
            int pageWidth = view.getWidth();

            if (position < -1) { // [-Infinity,-1)
                // This page is way off-screen to the left.
                view.setAlpha(0);

            } else if (position <= 0) { // [-1,0]
                // Use the default slide transition when moving to the left page
                view.setAlpha(1);
                view.setTranslationX(0);
                view.setScaleX(1);
                view.setScaleY(1);

            } else if (position <= 1) { // (0,1]
                // Fade the page out.
                view.setAlpha(1 - position);

                // Counteract the default slide transition
                view.setTranslationX(pageWidth * -position);

                // Scale the page down (between MIN_SCALE and 1)
                float scaleFactor = MIN_SCALE
                        + (1 - MIN_SCALE) * (1 - Math.abs(position));
                view.setScaleX(scaleFactor);
                view.setScaleY(scaleFactor);

            } else { // (1,+Infinity]
                // This page is way off-screen to the right.
                view.setAlpha(0);
            }
        }
    }

Поэтому я предполагаю, что нашел решение самостоятельно:

Прежде всего: Pinterest действительно использует ViewPager с настраиваемым Page Transformer, например, @frozenkoi, упомянутым в его ответе. В приложении pinterest вы можете увидеть эффект прокрутки плеера просмотра в приложении pinterest.

@Amit Gupta указал на библиотеку, которая позволила активности скользить. Его довольно такая же концепция, как и различные навигационные ящики, делает и тему полупрозрачной. Они сдвигают макет. Но это не совсем то, что я искал, потому что он перемещает верхнюю активность вправо и просто вызывает финиш (). Но нижняя активность не будет анимирована.

Решение (и, я думаю, это было Tumblr), чтобы написать свою собственную анимацию с объектами анимации и анимировать ее шаг за шагом. Это можно сделать с помощью ActivityOptions . По-моему, это будет решение.


Я имел дело с этим в проекте, над которым я сейчас работаю, и придумал следующий код. Возможно, это не относится к вам сейчас, но это может помочь кому-то новому в этом посте. :)

В основном это реализация ViewPager, как вы упомянули в своем ответе, но я думаю, что это самое простое и быстрое решение вашего вопроса. Недостатком является то, что это только для фрагментов (может быть легко изменено для объектов), и если вы хотите добавить ActionBar в салфетки, вы, вероятно, в конечном итоге создадите собственный.

public class DoubleViewPager extends FrameLayout implements ViewPager.OnPageChangeListener {

/**
 * Represents number of objects in DelegateViewPager. In others words it stands for one main content
 * window and one content detail window
 */
private static final int SCREEN_COUNT = 2;

private static final int CONTENT_SCREEN = 0;
private static final int DETAIL_SCREEN  = 1;


private DelegateViewPager delegateViewPager;
private SparseArray<Fragment> activeScreens = new SparseArray<Fragment>(SCREEN_COUNT) ;
private DelegateAdapter adapter;

public DoubleViewPager(Context context) {
    this(context, null);
}

public DoubleViewPager(Context context, AttributeSet attrs) {
    this(context, attrs, 0);
}

public DoubleViewPager(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);

    delegateViewPager = new DelegateViewPager(context);
    delegateViewPager.setId(R.id.main_page_id);
    delegateViewPager.setOverScrollMode(ViewPager.OVER_SCROLL_NEVER);
    final FrameLayout.LayoutParams params = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
            ViewGroup.LayoutParams.MATCH_PARENT, Gravity.CENTER);
    addView(delegateViewPager, params);
}

/**
 * Create a new PagerAdapter and set content fragment as a first object in ViewPager;
 * @param fragment Fragment you want to use as a main content
 * @param fm FragmentManager required for ViewPager transactions
 */
public void initialize(final Fragment fragment, final FragmentManager fm) {
    adapter = new DelegateAdapter(fm);
    delegateViewPager.setAdapter(adapter);
    activeScreens.put(CONTENT_SCREEN, fragment);
    adapter.notifyDataSetChanged();
}

/**
 * Adds fragment to stack and set it as current selected item. Basically it the same thing as calling
 * startActivity() with some transitions effects
 * @param fragment Fragment you want go into
 */
public void openDetailScreen(Fragment fragment) {
    activeScreens.put(DETAIL_SCREEN, fragment);
    adapter.notifyDataSetChanged();
    delegateViewPager.setCurrentItem(1, true);
}

public void hideDetailScreen() {
    delegateViewPager.setCurrentItem(CONTENT_SCREEN);
    if (activeScreens.get(DETAIL_SCREEN) != null) {
        activeScreens.remove(DETAIL_SCREEN);
        adapter.notifyDataSetChanged();
    }
}

@Override
public void onPageScrolled(int i, float v, int i2) {
    // unused
}

@Override
public void onPageSelected(int i) {
    if (i == CONTENT_SCREEN) hideDetailScreen();
}

@Override
public void onPageScrollStateChanged(int i) {
    // unused
}



private class DelegateViewPager extends ViewPager {

    public DelegateViewPager(Context context) {
        super(context);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        return getCurrentItem() != CONTENT_SCREEN && super.onInterceptTouchEvent(event);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        return getCurrentItem() != CONTENT_SCREEN && super.onTouchEvent(event);
    }
}

private final class DelegateAdapter extends FragmentPagerAdapter {

    public DelegateAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public Fragment getItem(int i) {
        return activeScreens.get(i);
    }

    @Override
    public int getCount() {
        return activeScreens.size();
    }
}

}

Вот активность, которая реализует его с помощью другого ViewPager как SlidingMenu. (как дополнительные)

public class DoubleViewPagerActivity extends FragmentActivity {

DoubleViewPager doubleViewPager;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_double_view_pager);

    doubleViewPager = (DoubleViewPager) findViewById(R.id.doublePager);
    doubleViewPager.initialize(new MainContentFragment(), getSupportFragmentManager());
}


public static final class MainContentFragment extends Fragment {

    public MainContentFragment() {

    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
        final View view = inflater.inflate(R.layout.fragment_doublepager_content_window, parent, false);
        final ViewPager pager = (ViewPager) view.findViewById(R.id.contentPager);
        pager.setAdapter(new SimpleMenuAdapter(getChildFragmentManager()));
        pager.setOffscreenPageLimit(2);
        pager.setCurrentItem(1);
        return view;
    }

}

public static final class SimpleMenuAdapter extends FragmentPagerAdapter {

    public SimpleMenuAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public Fragment getItem(int i) {
        return DoubleViewPagerActivity.PagerFragment.instance(i);
    }

    @Override
    public int getCount() {
        return 3;
    }

    @Override
    public float getPageWidth(int position) {
        switch (position) {
            case 0:
            case 2:
                return 0.7f;
        }
        return super.getPageWidth(position);
    }
}

public static final class PagerFragment extends Fragment {

    public static PagerFragment instance(int position) {
        final PagerFragment fr = new PagerFragment();
        Bundle args = new Bundle();
        args.putInt("position", position);
        fr.setArguments(args);
        return fr;
    }

    public PagerFragment() {

    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
        final FrameLayout fl = new FrameLayout(getActivity());
        fl.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.MATCH_PARENT));
        int position = getArguments().getInt("position");
        switch (position) {
            case 0:
                fl.setBackgroundColor(Color.RED);
                break;
            case 1:
                fl.setBackgroundColor(Color.GREEN);
                initListView(fl);
                break;
            case 2:
                fl.setBackgroundColor(Color.BLUE);
                break;
        }
        return fl;
    }

    private void initListView(FrameLayout fl) {
        int max = 50;
        final ArrayList<String> items = new ArrayList<String>(max);
        for (int i = 1; i <= max; i++) {
            items.add("Items " + i);
        }

        ListView listView = new ListView(getActivity());
        fl.addView(listView, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.MATCH_PARENT, Gravity.CENTER));
        listView.setAdapter(new ArrayAdapter<String>(getActivity(),
                android.R.layout.simple_list_item_1, items));

        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                ((DoubleViewPagerActivity) getActivity()).doubleViewPager.openDetailScreen(new DetailFragment());
            }
        });
    }
}

public final static class DetailFragment extends Fragment {

    public DetailFragment() {

    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
        FrameLayout l = new FrameLayout(getActivity());
        l.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.MATCH_PARENT));
        l.setBackgroundColor(getResources().getColor(android.R.color.holo_purple));
        return l;
    }

}

}


Я написал проект. Это позволяет вам легко разрабатывать приложение, ориентированное на Фрагменты, так же, как и Pinterest.

https://github.com/fengdai/FragmentMaster

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


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

package mobi.sherif.activitydrag;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener;
import android.view.animation.AnimationSet;
import android.view.animation.AnimationUtils;
import android.view.animation.LinearInterpolator;
import android.view.animation.TranslateAnimation;
import android.widget.FrameLayout.LayoutParams;

public class MainActivity extends Activity {
    private static final double PERCENT_OF_SCROLL_OF_ACTIVITY_TO_FINISH = 0.3;
    View mView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mView = LayoutInflater.from(this).inflate(R.layout.activity_main, null);
        setContentView(mView);
    }

    private boolean isDragging = false;
    int startX;
    int currentX;
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.v("sherif", isDragging?"YES":"NO" + ": " + event.getX());
        if(!isDragging) {
            if(event.getAction() == MotionEvent.ACTION_DOWN && event.getX()<24) {
                isDragging = true;
                startX = (int) event.getX();
                currentX = 0;
                return true;
            }
            return super.onTouchEvent(event);
        }
        switch(event.getAction()) {
        case MotionEvent.ACTION_MOVE:
            currentX = (int) event.getX() - startX;
            LayoutParams params = (LayoutParams) mView.getLayoutParams();
            params.leftMargin = currentX;
            params.rightMargin = -1 * currentX;
            mView.requestLayout();
            break;
        case MotionEvent.ACTION_UP:
        case MotionEvent.ACTION_CANCEL:
            isDragging = false;
            double currentPercent1 = (double) currentX / mView.getWidth();
            float currentPercent = (float) currentPercent1;
            if(currentX > PERCENT_OF_SCROLL_OF_ACTIVITY_TO_FINISH * mView.getWidth()) {
                AnimationSet animation = new AnimationSet(false);
                Animation anim = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, 1.0f - currentPercent, Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, 0.0f);
                anim.setDuration(getResources().getInteger(android.R.integer.config_mediumAnimTime));
                anim.setInterpolator(new LinearInterpolator());
                anim.setStartTime(AnimationUtils.currentAnimationTimeMillis());
                animation.addAnimation(anim);
                anim = new AlphaAnimation(1.0f, 0.5f);
                anim.setDuration(getResources().getInteger(android.R.integer.config_shortAnimTime));
                anim.setInterpolator(new LinearInterpolator());
                anim.setStartTime(AnimationUtils.currentAnimationTimeMillis());
                animation.addAnimation(anim);
                animation.setFillAfter(true);
                animation.setAnimationListener(new AnimationListener() {
                    @Override
                    public void onAnimationStart(Animation animation) {}
                    @Override
                    public void onAnimationRepeat(Animation animation) {}
                    @Override
                    public void onAnimationEnd(Animation animation) {
                        finish();
                    }
                });
                mView.startAnimation(animation);
            }
            else {
                AnimationSet animation = new AnimationSet(false);
                Animation anim = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, 0.0f -1 * currentPercent, Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, 0.0f);
                anim.setDuration(getResources().getInteger(android.R.integer.config_shortAnimTime));
                anim.setInterpolator(new LinearInterpolator());
                anim.setStartTime(AnimationUtils.currentAnimationTimeMillis());
                animation.addAnimation(anim);
                animation.setFillAfter(true);
                animation.setAnimationListener(new AnimationListener() {
                    @Override
                    public void onAnimationStart(Animation animation) {}
                    @Override
                    public void onAnimationRepeat(Animation animation) {}
                    @Override
                    public void onAnimationEnd(Animation animation) {
                        LayoutParams params = (LayoutParams) mView.getLayoutParams();
                        params.leftMargin = 0;
                        params.rightMargin = 0;
                        mView.requestLayout();
                        mView.clearAnimation();
                    }
                });
                mView.startAnimation(animation);
            }
            break;
        }
        return true;

    }
}

Я только что проверил с помощью просмотра иерархии. Похоже, что они используют ViewPager со снимком экрана предыдущей активности.





swipe