滚动多viewpagers效果 [英] Scrolling effect with multiple viewpagers

查看:168
本文介绍了滚动多viewpagers效果的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个观点的概念。请指导我一下,我如何实现它。请检查线框。

I have a concept for a view. Please guide me as to how I can achieve it. Please check the wireframe.

我已经看了Fa​​dingActionBar但它似乎并没有帮助。问题是我在屏幕上多viewpagers和我去任何地方试图达到预期的效果。这将是超级真棒,如果我能实现一个很酷的过渡/视差效果。

I have already looked at FadingActionBar but it does not seem to help. The problem is I have multiple viewpagers in the screen and am going no where trying to achieve the desired result. It would be super-awesome if I am able to achieve a cool transition/parallax effect.

所有的投入将大大AP preciated。

Any inputs will be much appreciated.

EDIT1:

的选项卡放在一个PagerTabStrip,并迷上了它下面的Viewpager。这里的尝试是滚动视图和停靠PagerTabStrip的动作条和向下滚动,把它归结为揭示ImageViewPager。

The tabs are put on a PagerTabStrip and hooked up with the Viewpager below it. The attempt here is to scroll the view and dock the PagerTabStrip to the ActionBar and on Scroll down bring it down to reveal the ImageViewPager.

推荐答案

所以,这可以很容易地实现pretty的,但它需要一个小动作,更像是一种幻觉实际。此外,我将使用一个的ListView ,而不是滚动型我的滚动的内容,主要是因为它更容易在这种情况下,为我的标签,我会使用该开源库。

So, this can be achieved pretty easily, but it requires a little trick, more like an illusion actually. Also, I'm going to be using a ListView instead of a ScrollView for my "scrollable content", mostly because it's easier to work with in this situation and for my tabs I'll be using this open sourced library.

首先,你需要一个查看可以存储y坐标为给定的指标。这个自定义的查看将被放置在您的底部之上 ViewPager 键,显示为每个真正的头文件的ListView 。你需要记住的头的y坐标在 ViewPager 每一页,所以你可以在用户之间刷卡以后恢复它们。我会扩大这一晚,但现在这里是什么查看应该是这样的:

First, you need a View that can store y-coordinates for a given index. This custom View will be placed on top of your bottom ViewPager and appear as the "real" header for each ListView. You need to remember the header's y-coordinate for each page in the ViewPager so you can restore them later as the user swipes between them. I'll expand on this later, but for now here's what that View should look like:

CoordinatedHeader

public class CoordinatedHeader extends FrameLayout {

    /** The float array used to store each y-coordinate */
    private final float[] mCoordinates = new float[5];

    /** True if the header is currently animating, false otherwise */
    public boolean mAnimating;

    /**
     * Constructor for <code>CoordinatedHeader</code>
     * 
     * @param context The {@link Context} to use
     * @param attrs The attributes of the XML tag that is inflating the view
     */
    public CoordinatedHeader(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    /**
     * Animates the header to the stored y-coordinate at the given index
     * 
     * @param index The index used to retrieve the stored y-coordinate
     * @param duration Sets the duration for the underlying {@link Animator}
     */
    public void restoreCoordinate(int index, int duration) {
        // Find the stored value for the index
        final float y = mCoordinates[index];
        // Animate the header to the y-coordinate
        animate().y(y).setDuration(duration).setListener(mAnimatorListener).start();
    }

    /**
     * Saves the given y-coordinate at the specified index, the animates the
     * header to the requested value
     * 
     * @param index The index used to store the given y-coordinate
     * @param y The y-coordinate to save
     */
    public void storeCoordinate(int index, float y) {
        if (mAnimating) {
            // Don't store any coordinates while the header is animating
            return;
        }
        // Save the current y-coordinate
        mCoordinates[index] = y;
        // Animate the header to the y-coordinate
        restoreCoordinate(index, 0);
    }

    private final AnimatorListener mAnimatorListener = new AnimatorListener() {

        /**
         * {@inheritDoc}
         */
        @Override
        public void onAnimationCancel(Animator animation) {
            mAnimating = false;
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public void onAnimationEnd(Animator animation) {
            mAnimating = false;
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public void onAnimationRepeat(Animator animation) {
            mAnimating = true;
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public void onAnimationStart(Animator animation) {
            mAnimating = true;
        }
    };

}

现在你可以为你的活动的主要布局片段。该布局包含底部 ViewPager CoordinatedHeader ;其中包括,底部 ViewPager 和标签。

Now you can create the main layout for your Activity or Fragment. The layout contains the bottom ViewPager and the CoordinatedHeader; which consists of, the bottom ViewPager and tabs.

主要布局

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <android.support.v4.view.ViewPager
        android:id="@+id/activity_home_pager"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <org.seeingpixels.example.widget.CoordinatedHeader
        android:id="@+id/activity_home_header"
        android:layout_width="match_parent"
        android:layout_height="250dp" >

        <android.support.v4.view.ViewPager
            android:id="@+id/activity_home_header_pager"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />

        <com.astuetz.viewpager.extensions.PagerSlidingTabStrip
            android:id="@+id/activity_home_tabstrip"
            android:layout_width="match_parent"
            android:layout_height="48dp"
            android:layout_gravity="bottom"
            android:background="@android:color/white" />
    </org.seeingpixels.example.widget.CoordinatedHeader>

</FrameLayout>

您唯一需要的其他布局是一个假的头。这种布局将被添加到每个的ListView ,使主布局的错觉 CoordinatedHeader 是真钞。

The only other layout you need is a "fake" header. This layout will be added to each ListView, giving the illusion the CoordinatedHeader in the main layout is the real one.

注意重要的是,这种布局的高度是一样的 CoordinatedHeader 在主体布局,在这个例子中,我使用 250dp

Note It's important that the height of this layout is the same as the CoordinatedHeader in the main layout, for this example I'm using 250dp.

假头

<View xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="250dp" />

现在你需要prepare每个片段将显示在底部 ViewPager 控制 CoordinatedHeader 通过附加 AbsListView.OnScrollListener 的ListView 。这片段也应该使用 Fragment.setArguments 通过在创建唯一索引。该指数应该重新present其位置 ViewPager

Now you need to prepare each Fragment that will be displayed in the bottom ViewPager to control the CoordinatedHeader by attaching a AbsListView.OnScrollListener to your ListView. This Fragment should also pass a unique index upon creation using Fragment.setArguments. This index should represent its location in the ViewPager.

注意我在这个例子中使用 ListFragment

Note I'm using a ListFragment in this example.

滚动内容片段

Scrollable content Fragment

/**
 * {@inheritDoc}
 */
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    final Activity a = getActivity();

    final ListView list = getListView();
    // Add the fake header
    list.addHeaderView(LayoutInflater.from(a).inflate(R.layout.view_fake_header, list, false));

    // Retrieve the index used to save the y-coordinate for this Fragment
    final int index = getArguments().getInt("index");

    // Find the CoordinatedHeader and tab strip (or anchor point) from the main Activity layout
    final CoordinatedHeader header = (CoordinatedHeader) a.findViewById(R.id.activity_home_header);
    final View anchor = a.findViewById(R.id.activity_home_tabstrip);

    // Attach a custom OnScrollListener used to control the CoordinatedHeader 
    list.setOnScrollListener(new OnScrollListener() {

        @Override
        public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
                int totalItemCount) {

            // Determine the maximum allowed scroll height
            final int maxScrollHeight = header.getHeight() - anchor.getHeight();

            // If the first item has scrolled off screen, anchor the header
            if (firstVisibleItem != 0) {
                header.storeCoordinate(index, -maxScrollHeight);
                return;
            }

            final View firstChild = view.getChildAt(firstVisibleItem);
            if (firstChild == null) {
                return;
            }

            // Determine the offset to scroll the header
            final float offset = Math.min(-firstChild.getY(), maxScrollHeight);
            header.storeCoordinate(index, -offset);
        }

        @Override
        public void onScrollStateChanged(AbsListView view, int scrollState) {
            // Nothing to do
        }

    });
}

最后,你需要设置协调头,当用户使用 ViewPager.OnPageChangeListener页面之间挥笔,以恢复其y坐标

Finally, you'll need to setup the Coordinated header to restore its y-coordinates when the user swipes between pages using a ViewPager.OnPageChangeListener.

注意当把你的 PagerAdapter 您的底部 ViewPager ,重要的是要打电话 ViewPager.setOffscreenPageLimit ,并设置金额的网页在您 PagerAdapter 的总量。这是为了让 CoordinatedHeader 可存储的y坐标为每个片段向右走,否则你会遇到麻烦它是不同步的。

Note When attaching your PagerAdapter to your bottom ViewPager, it's important to call ViewPager.setOffscreenPageLimit and set that amount to the total amount of pages in your PagerAdapter. This is so the CoordinatedHeader can store the y-coordinate for each Fragment right away, otherwise you'll run into trouble with it being out of sync.

主要活动

Main Activity

/**
 * {@inheritDoc}
 */
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_home);

    // Setup the top PagerAdapter
    final PagerAdapter topAdapter = new PagerAdapter(getFragmentManager());
    topAdapter.buildData(DummyColorFragment.newInstance(Color.RED));
    topAdapter.buildData(DummyColorFragment.newInstance(Color.WHITE));
    topAdapter.buildData(DummyColorFragment.newInstance(Color.BLUE));

    // Setup the top pager
    final ViewPager topPager = (ViewPager) findViewById(R.id.activity_home_header_pager);
    topPager.setAdapter(topAdapter);

    // Setup the bottom PagerAdapter
    final PagerAdapter bottomAdapter = new PagerAdapter(getFragmentManager());
    bottomAdapter.buildData(DummyListFragment.newInstance(0));
    bottomAdapter.buildData(DummyListFragment.newInstance(1));
    bottomAdapter.buildData(DummyListFragment.newInstance(2));
    bottomAdapter.buildData(DummyListFragment.newInstance(3));
    bottomAdapter.buildData(DummyListFragment.newInstance(4));

    // Setup the bottom pager
    final ViewPager bottomPager = (ViewPager) findViewById(R.id.activity_home_pager);
    bottomPager.setOffscreenPageLimit(bottomAdapter.getCount());
    bottomPager.setAdapter(bottomAdapter);

    // Setup the CoordinatedHeader and tab strip
    final CoordinatedHeader header = (CoordinatedHeader) findViewById(R.id.activity_home_header);
    final PagerSlidingTabStrip psts = (PagerSlidingTabStrip) findViewById(R.id.activity_home_tabstrip);
    psts.setViewPager(bottomPager);
    psts.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
        @Override
        public void onPageScrollStateChanged(int state) {
            if (state != ViewPager.SCROLL_STATE_IDLE) {
                // Wait until the pager is idle to animate the header
                return;
            }
            header.restoreCoordinate(bottomPager.getCurrentItem(), 250);
        }
    });
}

这篇关于滚动多viewpagers效果的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆