Android仿小紅書啟動頁平行動畫
其實之前在很多APP的引導(dǎo)頁上都看到過這個效果,通過速度不同給人帶來視覺差,感覺很炫酷。
通過網(wǎng)易云的課做了一個demo,記錄一下。

首先來梳理一下實現(xiàn)的思路,其實就是viewpager+fragment,只不過這個fragment里的控件,會根據(jù)viewpager的滑動產(chǎn)生不同的速度的位移。從架構(gòu)的角度來考慮的話,我們要做到可以隨時添加fragment,同時可以隨時添加fragment里的控件,控件的速度可以設(shè)置。所以要給系統(tǒng)控件來添加自定義屬性。
attrs文件
//進(jìn)入的時候透明度 //出去的時候透明度 //進(jìn)入的時候x方向的速度 //出去的時候x方向的速度 //進(jìn)入的時候Y方向的速度 出去的時候Y方向的速度
android:id="@+id/iv_0"android:layout_width="103dp"android:layout_height="19dp"android:layout_centerInParent="true"android:src="@drawable/intro1_item_0"app:x_in="1.2"app:x_out="1.2" />
自定義FrameLayout
public void setUp(int... childIds) {//fragment集合fragments = new ArrayList(); for (int i = 0; i < childIds.length; i++) {ParallaxFragment fragment = new ParallaxFragment();//通過bundle傳遞參數(shù)給fragmentBundle bundle = new Bundle();bundle.putInt("layoutId", childIds[i]);fragment.setArguments(bundle);fragments.add(fragment);}ViewPager vp = new ViewPager(getContext());vp.setId(R.id.parallax_pager);//從value里的ids拿的SplashActivity activity = (SplashActivity) getContext();parallaxPagerAdapter = new ParallaxPagerAdapter(activity.getSupportFragmentManager(), fragments);vp.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));vp.setAdapter(parallaxPagerAdapter);vp.setOnPageChangeListener(this);addView(vp,0);}
自定義Fragment
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {//獲取到布局文件idint rootViewId = getArguments().getInt("layoutId");//自定義LayoutInflater來處理里面的控件ParallaxLayoutInflater parallaxLayoutInflater = new ParallaxLayoutInflater(inflater,getActivity(),this);View rootView = parallaxLayoutInflater.inflate(rootViewId, null);return rootView;}
自定義LayoutInflater
class ParallaxFactory implements Factory2 {private LayoutInflater layoutInflater;//系統(tǒng)控件的前綴private String[] sClassPrefix = {"android.widget.","android.view."};//系統(tǒng)控件自定義的屬性int[] attrIds = {R.attr.a_in,R.attr.a_out,R.attr.x_in,R.attr.x_out,R.attr.y_in,R.attr.y_out};public ParallaxFactory(LayoutInflater layoutInflater) {this.layoutInflater = layoutInflater;}/*** 反射機(jī)制** @param parent 頂級容器* @param name 控件名字(像RelativeLayout,ImageView)如果是自定義控件的話 返回的是全路徑名字* @param context* @param attrs 控件的屬性(width,height)* @return*/@Overridepublic View onCreateView(View parent, String name, Context context, AttributeSet attrs) {View view = null;view = createMyView(name, context, attrs);if (view != null) {//attrs 控件的所有屬性,attrIds 是想要獲取的控件的屬性TypedArray array = context.obtainStyledAttributes(attrs, attrIds);if (array != null && array.length() > 0) {ParallaxViewTag viewTag = new ParallaxViewTag();viewTag.alphaIn = array.getFloat(0, 0f);viewTag.alphaOut = array.getFloat(1, 0f);viewTag.xIn = array.getFloat(2, 0f);viewTag.xOut = array.getFloat(3, 0f);viewTag.yIn = array.getFloat(4, 0f);viewTag.yOut = array.getFloat(5, 0f);view.setTag(R.id.parallax_view_tag, viewTag);}fragment.getParallaxViews().add(view);array.recycle();}return view;}/*** 創(chuàng)建view* @param name* @param context* @param attrs* @return*/private View createMyView(String name, Context context, AttributeSet attrs) {//如果是系統(tǒng)的控件,不會有. 如果是自定義控件的話 含有.if (name.contains(".")) {return reflectView(name, null, attrs);} else {//循環(huán)兩個包for (String prefix : sClassPrefix) {View view = reflectView(name, prefix, attrs);if (view != null) {return view;}}}return null;}/*** @param name 控件名字* @param prefix 控件前綴* @param attrs 控件屬性* @return*/private View reflectView(String name, String prefix, AttributeSet attrs) {try {//通過系統(tǒng)的layoutInflater創(chuàng)建視圖,讀取系統(tǒng)屬性return layoutInflater.createView(name, prefix, attrs);} catch (ClassNotFoundException e) {e.printStackTrace();}return null;}@Overridepublic View onCreateView(String name, Context context, AttributeSet attrs) {return null;}}
@Overridepublic void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {//動畫操作int containerWidth = getWidth();//獲取到退出ParallaxFragment outFragment = null;try {outFragment = fragments.get(position - 1);} catch (Exception e) {e.printStackTrace();}//獲取到進(jìn)入的頁面ParallaxFragment inFragment = null;try {inFragment = fragments.get(position);} catch (Exception e) {}if (outFragment != null) {//獲取Fragment上所有的視圖,實現(xiàn)動畫效果ListinViews = outFragment.getParallaxViews(); // 動畫if (inViews != null) {for (View view : inViews) {ParallaxViewTag tag = (ParallaxViewTag) view.getTag(R.id.parallax_view_tag);if (tag == null) {continue;}ViewHelper.setTranslationX(view, (containerWidth - positionOffsetPixels) * tag.xIn);ViewHelper.setTranslationY(view, (containerWidth - positionOffsetPixels) * tag.yIn);}}}if (inFragment != null) {ListoutViews = inFragment.getParallaxViews(); if (outViews != null) {for (View view : outViews) {ParallaxViewTag tag = (ParallaxViewTag) view.getTag(R.id.parallax_view_tag);if (tag == null) {continue;}//仔細(xì)觀察退出的fragment中view從原始位置開始向上移動,translationY應(yīng)為負(fù)數(shù)ViewHelper.setTranslationY(view, 0 - positionOffsetPixels * tag.yOut);ViewHelper.setTranslationX(view, 0 - positionOffsetPixels * tag.xOut);}}????????}}
評論
圖片
表情
