Подтвердить что ты не робот

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

Есть ли у кого-нибудь идея, как Pinterest или Tumblr реализовали там метод "проведите назад".

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

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

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

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

Любые предложения?

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

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

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


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

4b9b3361

Ответ 1

Итак, я думаю, что нашел решение самостоятельно:

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

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

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

Ответ 2

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

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

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

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

Ответ 3

Update: проблема с фиксированной памятью для этого проекта и изменила стиль слайдов назад на iOS.

введите описание изображения здесь

Я написал демоверсию точно так же, как Pinterest и tumblr вроде, вы просто расширяете BaseActivity, и вы получаете эффект обратного движения, работает плавно!

проверьте это: https://github.com/chenjishi/SlideActivity

и снимок экрана: enter image description here

Ответ 4

Я нашел проект GitHub, основанный на SwipeBack как Pinterest.

Это действительно отличный проект с открытым исходным кодом, который должен решить вашу проблему. Он делает то, что вам нужно, например, переходить на предыдущий экран, нажимая назад или просто проведите пальцем по экрану. Поскольку этот проект имеет опцию

1. Проведите пальцем влево вправо

2. Проведите по экрану справа налево

3. Проведите вниз вверх

https://github.com/Issacw0ng/SwipeBackLayout

, а также установить это демо-приложение из Google Play.

https://play.google.com/store/apps/details?id=me.imid.swipebacklayout.demo

Прикрепленные скриншоты: -

enter image description here

Надеюсь, это поможет вам.

Ответ 5

Я смог сделать это за 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;

    }
}

Ответ 6

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

Ответ 7

Я предлагаю сделать следующее:

Сначала определите жест, который пользователь делает в устройстве. Вы можете обратиться к этой ссылке

Я не собираюсь копировать соответствующий код из приведенной выше ссылки, так как я считаю, что это принятый ответ

Во-вторых, вы можете в этом методе

public void onSwipeLeft() {
    Toast.makeText(MyActivity.this, "left", Toast.LENGTH_SHORT).show();
}

Сделайте следующее, предложенное этим вопросом

Они там говорят о завершении работы с анимацией

Look into doing it through a theme. You can define enter exit animations for activities or the entire application

Надеюсь, это поможет вам

Ответ 8

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

https://github.com/fengdai/FragmentMaster

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

Ответ 9

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

В основном это реализация 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;
    }

}

}