利用view pager和recycler view兩種控制元件寫出有圓點指示器的引導頁
最終效果:
(viewpager方式和recyclerview方式實現效果相同,但是recyclerview沒有轉場動畫)。
- view pager
viewpager寫引導頁是比較簡單常見的,思路:
1.沉浸式狀態列。
2.建立viewpager並將圖片資料通過adapter設定給viewpager
3.圓點指示器
4.設定切換動畫
1.沉浸式狀態列之前有了解過,在沒有用residemenu等第三方庫的時候,在Android4.4以上通過一下方法能夠成功。
/** * 透明化狀態列 */ public static void TranslucentStatusBar(Activity activity) { activity.getWindow().requestFeature(Window.FEATURE_NO_TITLE); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { Window window = activity.getWindow(); window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION); window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_STABLE); window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); window.setStatusBarColor(Color.TRANSPARENT); window.setNavigationBarColor(Color.TRANSPARENT); } }
2.建立viewpager等程式碼
<android.support.v4.view.ViewPager android:id="@+id/view_pager" android:layout_width="match_parent" android:layout_height="match_parent" /> viewPager = (ViewPager) findViewById(R.id.view_pager); private List<View> mList = {…}; for (int i = 0; i < mImages.length; i++) { ImageView imageView = new ImageView(this); imageView.setScaleType(ImageView.ScaleType.CENTER_CROP); imageView.setImageResource(mImages[i]); mList.add(imageView); } PagerAdapter pagerAdapter = new PagerAdapter() { @Override public boolean isViewFromObject(View arg0, Object arg1) { return arg0 == arg1; } @Override public int getCount() { return mList.size(); } @Override public void destroyItem(ViewGroup container, int position, Object object) { container.removeView(mList.get(position)); } @Override public Object instantiateItem(ViewGroup container, int position) { container.addView(mList.get(position)); return mList.get(position); } }; viewPager.setAdapter(pagerAdapter);
3.建立圓點指示器之前沒有寫過,通過查詢資料發現可通過 linearlayout.addView方式新增小圓點群,通過position判斷當前圓點是否被選中 ,從而顯示不同的drawable。
程式碼如下:
<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:drawable="@drawable/ic_select" android:state_selected="true" /> <item android:drawable="@drawable/ic_unselect" android:state_selected="false"/> </selector> <LinearLayout android:id="@+id/point_group" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true" android:layout_marginBottom="72dp" android:orientation=“horizontal”></LinearLayout> pointGroup = (LinearLayout) findViewById(R.id.point_group); for (int i = 0; i < mImages.length; i++) { ImageView pointImage = new ImageView(this); pointImage.setImageResource(R.drawable.pointgroup); int PointSize = getResources().getDimensionPixelSize(R.dimen.point_size); LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(PointSize, PointSize); if (i > 0) { params.leftMargin = getResources().getDimensionPixelSize(R.dimen.point_margin); pointImage.setSelected(false); } else { pointImage.setSelected(true); } pointImage.setLayoutParams(params); pointGroup.addView(pointImage); }
首先設定R.drawable.point_group.根據select的值顯示不同的drawable
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
int lastPosition;
@Override
public void onPageSelected(int position) {
pointGroup.getChildAt(position).setSelected(true);
pointGroup.getChildAt(lastPosition).setSelected(false);
lastPosition = position;
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
}
然後設定linearlayout。
然後設定viewpager的滑動監聽器pagechangelistener, 當前位置設定為被選擇,當前位置的前一個位置設為不被選擇,當前位置後一個位置(如果有的話)還沒有被設定,所以為未選擇。
4.設定切換動畫,通過viewpager的setpagetransformer方法,判斷當前位置是否顯示,設定透明度偏移量等等。
viewPager.setPageTransformer(true, new ViewPager.PageTransformer() {
private static final float MIN_SCALE = 0.75f;
@Override
public void transformPage(View view, float position) {
int pageWidth = view.getWidth();
if (position < -1) { // [-Infinity,-1)
view.setAlpha(0);
} else if (position <= 0) { // [-1,0]
view.setAlpha(1);
view.setTranslationX(0);
view.setScaleX(1);
view.setScaleY(1);
} else if (position <= 1) { // (0,1]
view.setAlpha(1 - position);
view.setTranslationX(pageWidth * -position);
float scaleFactor = MIN_SCALE
+ (1 - MIN_SCALE) * (1 - Math.abs(position));
view.setScaleX(scaleFactor);
view.setScaleY(scaleFactor);
} else { // (1,+Infinity]
view.setAlpha(0);
}
}
});
到這裡,viewpager的引導頁就基本完成了,也可以在最後一頁去掉圓點指示器,加上“立即體驗”按鈕,只需在onpagechangelistener中判斷位置是否是最後一頁,然後對控制元件setvisibility就可以了。
- recycler view
利用recyclerview來做就不是那麼容易了,思路:
1.沉浸式狀態列。
2.建立recyclerview,adapter和資料繫結,並設定為橫向。
3.讓每一個item自動滑動到螢幕中央,且每次只能滑動一頁item。
private void initPoint() {
//指示器部分
layout = (RelativeLayout) findViewById(R.id.layout_view);
pointRecyclerView = new RecyclerView(RSplashActivity.this);
LinearLayoutManager indicatorLayoutManager = new LinearLayoutManager(RSplashActivity.this
, LinearLayoutManager.HORIZONTAL, false);
pointRecyclerView.setLayoutManager(indicatorLayoutManager);
pointAdapter = new PointAdapter();
pointRecyclerView.setAdapter(pointAdapter);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
params.addRule(RelativeLayout.CENTER_HORIZONTAL);
params.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
params.bottomMargin = dp2px(72);
layout.addView(pointRecyclerView, params);
}
public class PointAdapter extends RecyclerView.Adapter {
int currentPosition = 0;
public void setPosition(int position) {
this.currentPosition = position;
}
@SuppressLint("ResourceAsColor")
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
ImageView imageView = new ImageView(RSplashActivity.this);
RecyclerView.LayoutParams lp = new RecyclerView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
lp.setMargins(dp2px(7), dp2px(7), dp2px(7), dp2px(7));
imageView.setLayoutParams(lp);
return new RecyclerView.ViewHolder(imageView) {
};
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
ImageView bannerPoint = (ImageView) holder.itemView;
bannerPoint.setImageResource(currentPosition == position ?
R.drawable.ic_select : R.drawable.ic_unselect);
}
@Override
public int getItemCount() {
return mImages.length;
}
}
protected synchronized void refreshIndicator() {
pointAdapter.setPosition(currentIndex % 3);
pointAdapter.notifyDataSetChanged();
}
protected int dp2px(int dp) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp,
Resources.getSystem().getDisplayMetrics());
}
4.圓點指示器的設定。
1.沉浸式狀態列同viewpager。
2.比較容易,程式碼省略。
3.利用snaphelp來解決問題
final PagerSnapHelper snapHelper = new PagerSnapHelper();
snapHelper.attachToRecyclerView(recyclerView);
4.圓點指示器這一步比較難,主要是監聽item的改變並根據位置設定圓點是否選中。當時的思路有以下幾種:
- 通過recyclerview中的onfing能夠監聽滑動位移x,y,將x與測試機螢幕寬度做對比,若成倍數則表示剛好滑動到某個item,則可根據倍數判斷在哪一個位置,從而設定圓點。但是測試得知onfing中獲得的x並不與螢幕畫素點成倍數,故此方法不可行。
- 通過snaphelper的findtargetsnapposition來獲取當前item位置,通過recyclerview的onscrollchangelistener來監聽,但通過輸出發現此方法也不能準確輸出當前position。
- 通過linearlayoutmanager中監聽方法,但搜尋方法並沒有類似方法。
- 在recyclerview的item中寫好圓點指示器,在adapter通過onbindviewholder中的position來設定圓點指示器,此方法可行,但滑動頁面是圓點指示器也會隨之滑動,故不符合頁面效果。
最後在github上某個demo中看到可行方法並應用到自己demo中,思路是在onscrolled中通過linearlayoutmanager中的方法計算獲得當前position,並在onbindviewholder中動態建立圓點指示器。以下是程式碼:
就是整體把圓點指示器當作recyclerview來做,利用adpater的特性,根據currentIndex的改變來動態更新指示器的drawable。到此,recyclerview的引導頁也實現了。
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
}
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
int firstReal = linearLayoutManager.findFirstVisibleItemPosition();
View viewFirst = linearLayoutManager.findViewByPosition(firstReal);
if (width != 0 && viewFirst != null) {
float right = viewFirst.getRight();
float ratio = right / width;
if (ratio > 0.8) {
if (currentIndex != firstReal) {
currentIndex = firstReal;
refreshIndicator();
}
} else if (ratio < 0.2) {
if (currentIndex != firstReal + 1) {
currentIndex = firstReal + 1;
refreshIndicator();
}
}
}
}
});
完整程式碼地址:http://download.csdn.net/download/denglixuan1996/10264986