Android仿小红书启动页平行动画
龙旋
共 6863字,需浏览 14分钟
·
2021-10-24 14:33
其实之前在很多APP的引导页上都看到过这个效果,通过速度不同给人带来视觉差,感觉很炫酷。
通过网易云的课做了一个demo,记录一下。
首先来梳理一下实现的思路,其实就是viewpager+fragment,只不过这个fragment里的控件,会根据viewpager的滑动产生不同的速度的位移。从架构的角度来考虑的话,我们要做到可以随时添加fragment,同时可以随时添加fragment里的控件,控件的速度可以设置。所以要给系统控件来添加自定义属性。
attrs文件
//进入的时候透明度
//出去的时候透明度
//进入的时候x方向的速度
//出去的时候x方向的速度
//进入的时候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传递参数给fragment
Bundle 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) {
//获取到布局文件id
int 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;
//系统控件的前缀
private String[] sClassPrefix = {
"android.widget.",
"android.view."
};
//系统控件自定义的属性
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;
}
/**
* 反射机制
*
* @param parent 顶级容器
* @param name 控件名字(像RelativeLayout,ImageView)如果是自定义控件的话 返回的是全路径名字
* @param context
* @param attrs 控件的属性(width,height)
* @return
*/
@Override
public 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;
}
/**
* 创建view
* @param name
* @param context
* @param attrs
* @return
*/
private View createMyView(String name, Context context, AttributeSet attrs) {
//如果是系统的控件,不会有. 如果是自定义控件的话 含有.
if (name.contains(".")) {
return reflectView(name, null, attrs);
} else {
//循环两个包
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 {
//通过系统的layoutInflater创建视图,读取系统属性
return layoutInflater.createView(name, prefix, attrs);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
@Override
public View onCreateView(String name, Context context, AttributeSet attrs) {
return null;
}
}
@Override
public 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();
}
//获取到进入的页面
ParallaxFragment inFragment = null;
try {
inFragment = fragments.get(position);
} catch (Exception e) {
}
if (outFragment != null) {
//获取Fragment上所有的视图,实现动画效果
List
inViews = 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) {
List
outViews = inFragment.getParallaxViews(); if (outViews != null) {
for (View view : outViews) {
ParallaxViewTag tag = (ParallaxViewTag) view.getTag(R.id.parallax_view_tag);
if (tag == null) {
continue;
}
//仔细观察退出的fragment中view从原始位置开始向上移动,translationY应为负数
ViewHelper.setTranslationY(view, 0 - positionOffsetPixels * tag.yOut);
ViewHelper.setTranslationX(view, 0 - positionOffsetPixels * tag.xOut);
}
}
}
}
评论