我有一个观点的概念。请指导我如何实现它。请检查线框。
我已经看过FadingActionBar,但它似乎没有帮助。问题是我在屏幕上有多个观看者,并且在试图达到预期结果时没有。如果我能够实现很酷的过渡/视差效果,那将是非常棒的。
非常感谢任何投入。
Edit1:
选项卡放在PagerTabStrip上,并与其下方的Viewpager连接。这里的尝试是滚动视图并将PagerTabStrip停靠到ActionBar,然后向下滚动将其调低以显示ImageViewPager。
答案 0 :(得分:14)
所以,这可以很容易地实现,但它需要一个小技巧,更像是幻觉。此外,我将使用ListView
代替ScrollView
作为我的“可滚动内容”,主要是因为在这种情况下我更容易使用,而且我将使用{ {3}}
首先,您需要一个View
来存储给定索引的y坐标。此自定义View
将置于您的底部ViewPager
之上,并显示为每个ListView
的“真实”标题。您需要记住ViewPager
中每个页面的标题y坐标,以便稍后在用户在它们之间滑动时可以恢复它们。我稍后会对此进行扩展,但现在这就是View
应该是这样的:
<强> 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;
}
};
}
现在,您可以为Activity
或Fragment
创建主要布局。布局包含底部ViewPager
和CoordinatedHeader
;它由底部ViewPager
和标签组成。
主要布局
<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
是真实的。
注意此布局的高度与主布局中的CoordinatedHeader
相同非常重要,对于此示例,我使用250dp
。
假标题
<View xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="250dp" />
现在,您需要准备将显示在Fragment
底部的每个ViewPager
,以通过将CoordinatedHeader
附加到AbsListView.OnScrollListener
来控制ListView
。此Fragment
也应在使用Fragment.setArguments
创建时传递唯一索引。该索引应表示其在ViewPager
中的位置。
注意我在此示例中使用了ListFragment
。
可滚动内容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
}
});
}
最后,当用户使用Coordinated
在页面之间滑动时,您需要设置ViewPager.OnPageChangeListener
标头以恢复其y坐标。
注意将PagerAdapter
附加到底部ViewPager
时,请务必致电ViewPager.setOffscreenPageLimit
并将该金额设置为PagerAdapter
中的总页数{1}}。这样CoordinatedHeader
可以立即存储每个Fragment
的y坐标,否则会因为它不同步而遇到麻烦。
主要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);
}
});
}
答案 1 :(得分:2)
您也可以使用 Android-ParallaxHeaderViewPager 来实现此效果,这是通过kmshack Github page滚动标签标题的一个很好的示例
示例代码在此Here Git Hub link
中给出这是屏幕截图
@adneal的解决方案对于实现滚动Tab标题非常有用。
跳这会帮助你
新更新
答案 2 :(得分:0)
我使用片段容器布局而不是使用FadingActionBar的viewpager。我也使用MaterialTabs库。
内容布局
//And populate both set on tab
private void populateTabStrip() {
final PagerAdapter adapter = mViewPager.getAdapter();
final OnClickListener tabClickListener = new TabClickListener();
for (int i = 0; i < adapter.getCount(); i++) {
View tabView = null;
TextView tabTitleView = null;
if (tabView == null) {
tabView = createDefaultTabView(getContext());
}
if (tabTitleView == null && TextView.class.isInstance(tabView)) {
tabTitleView = (TextView) tabView;
}
//Also want to set some selector here
tabTitleView.setText(adapter.getPageTitle(i));
if (mViewPager.getCurrentItem() == i) {
tabTitleView.setSelected(true);
}
tabTitleView.setTextColor(R.color.white);
mTabStrip.addView(tabView);
}
}
<强>活动强>
<xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:attr/windowBackground"
android:orientation="vertical">
<it.neokree.materialtabs.MaterialTabHost
android:id="@+id/materialTabHost"
android:layout_width="match_parent"
android:layout_height="48dp"
app:accentColor="@color/second"
app:primaryColor="@color/actionbar_background"
app:textColor="#FFFFFF" />
<FrameLayout
android:id="@+id/container"
android:layout_width="wrap_content"
android:layout_height="match_parent">
</FrameLayout>
</LinearLayout>
最后有一个结果:link(gif)