先上一个效果图,看一下实现效果
大概说明一下:最外层布局,是ViewPager,子项是Fragment,一屏幕显示5个子项,中间位置突出,两侧子项缩放,并且隐藏在中间子项后边,用阴影显示
外层布局就是一个ViewPager,先定义好:
两点说明:1.android:clipChildren,是否限制子View在其范围内,默认值为true,也就是不允许进行扩展绘制,这里设置为false,还必须是在ViewPager的父布局设置
2.android:layout_margin=“40dp”, 设置这个,是为了给ViewPager两侧留出多余位置,用来显示两侧阴影
首先:Fragment里,外层布局是FrameLayout,里边有两个布局,一个是正常显示,一个是用来改变透明度,实现阴影效果,这个以后会根据滑动位置,来切换显示不同布局,先定义两个圆角矩形,一个是有阴影外层,作为正常显示布局的背景,另一个是纯色,作为另一个布局的背景
1.实现有阴影外层的圆角矩形
这个是用layer-list
-
-
2.纯色的圆角矩形
有了这两个背景,剩下的就是布局,也很简单
3.进度条效果:
布局中,有一个进度条的效果,实现这样的效果,也是需要使用layer-list,但是自定义的时候,希望进度条两侧都是圆角矩形,但是一般会clip成直角,这个解决方法,是自定义个shape去引用
-
-
progress_bar_ct.xml
-
Android布局实现阴影效果
Fragment作为演示,功能很简单,根据定义,加载不同图片
public class PictureFragment extends Fragment
{
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
// TODO: Rename and change types of parameters
private int mParam1;
public PictureFragment()
{
// Required empty public constructor
}
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* @param param1 Parameter 1.
* @return A new instance of fragment PictureFragment.
*/
// TODO: Rename and change types and number of parameters
public static PictureFragment newInstance(int param1)
{
PictureFragment fragment = new PictureFragment();
Bundle args = new Bundle();
args.putInt(ARG_PARAM1, param1);
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
if (getArguments() != null)
{
mParam1 = getArguments().getInt(ARG_PARAM1);
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_picture, container, false);
ImageView imageView = (ImageView) view.findViewById(R.id.iv_image);
imageView.setBackgroundResource(mParam1);
return view;
}
@Override
public void onAttach(Context context)
{
super.onAttach(context);
}
@Override
public void onDetach()
{
super.onDetach();
}
}
{
.............
fragments.add(PictureFragment.newInstance(R.mipmap.p1));
fragments.add(PictureFragment.newInstance(R.mipmap.p2));
fragments.add(PictureFragment.newInstance(R.mipmap.p3));
fragments.add(PictureFragment.newInstance(R.mipmap.p4));
fragments.add(PictureFragment.newInstance(R.mipmap.p5));
fragments.add(PictureFragment.newInstance(R.mipmap.p6));
fragments.add(PictureFragment.newInstance(R.mipmap.p7));
CustomPagerAdapter customPagerAdapter = new CustomPagerAdapter(getSupportFragmentManager(), fragments);
viewPager.setPageTransformer(true, new CustomTransformer(DemoActivity.this));
viewPager.setAdapter(customPagerAdapter);
viewPager.setOffscreenPageLimit(5);
}
public class CustomPagerAdapter extends FragmentStatePagerAdapter
{
private List mFragments;
public CustomPagerAdapter(FragmentManager fm, List fragments)
{
super(fm);
this.mFragments = fragments;
fm.beginTransaction().commitAllowingStateLoss();
}
@Override
public Fragment getItem(int position)
{
return this.mFragments.get(position);
}
@Override
public int getCount()
{
return this.mFragments.size();
}
@Override
public int getItemPosition(@NonNull Object object)
{
return PagerAdapter.POSITION_NONE;
}
}
说明:1.Viewpager的setOffscreenPageLimit(int limit)方法,设置有多少的缓存Views
2.Viewpager的setPageTransformer(boolean reverseDrawingOrder, ViewPager.PageTransformer transformer)方法的第一个参数,用来控制加入到Viewpager的Views对象是正序的还是倒序的
Viewpager实现特效,主要通过PageTransformer接口,不熟悉的可以先了解一下
Android ViewPager.PageTransformer详解
Android——ViewPager实现3D画廊效果
ViewPager实现层叠卡片
Android ViewPager使用方法小结
现在开始实现效果图中的特效:
1.正常情况下,子项是不折叠到一起,通过设置 view.setTranslationX,按照子项宽度进行和位置进行平移,这样才能折叠到一起,pageWidth* position,为了实现效果图上左右两侧露出部分,可以通过改变偏移量实现,比如pageWidth * 0.9f * position之类
2.实现中间位置突出。设置折叠后,正常情况下,后边子项会遮盖在前一子项上边,这个通过设置setTranslationZ可以改变,这个translationZ设置view的层级,translationZ越大,说明他的层级越高,所以position = -1的view的层级就比position=0的view的层级低,那么position=0的view就会叠在position=-1的view的上面,除中间位置以外,其他子项,都设置低一些,这样才能突出中间子项
3.缩放可以通过view.setScaleX和 view.setScaleY来实现,设置不同的值,缩放不同的大小,通过这个,可以实现,最外层比次外层小的效果
4.除中间位置以外,其他位置,切换到纯色背景,设置透明度,
public class CustomTransformer implements ViewPager.PageTransformer
{
private static final float MIN_SCALE = 0.85f;
private static final float MIN_ALPHA = 0.8f;
private static float defaultScale = 0.5f;
private Context context;
public CustomTransformer(Context context)
{
this.context = context;
}
@Override
public void transformPage(View view, float position)
{
int pageWidth = view.getWidth();
int pageHeight = view.getHeight();
float scaleFactor = Math.max(MIN_SCALE, 1 - Math.abs(position));
//一个页面显示5个子项,最左侧的位置是-2,小于-2的,设置透明度为0,隐藏
if (position < -2)
{
view.setAlpha(0);
view.setScaleX(defaultScale);
view.setScaleY(defaultScale);
}
else if (position >= -2 && position <= -1)
{ //中间位置左侧的两个子项
//设置透明度
view.setAlpha(0.1f);
// view.setAlpha((MIN_ALPHA + (scaleFactor - MIN_SCALE) / (1 - MIN_SCALE) * (1 - MIN_ALPHA))*0.5f);
if (position < -1 && position >= -2)//最左侧子项,比前一子项缩放更小一些
{
view.setScaleX(scaleFactor * 0.9f);
view.setScaleY(scaleFactor * 0.9f);
}
else
{
view.setScaleX(scaleFactor);
view.setScaleY(scaleFactor);
}
/**
这个translationZ设置view的层级,translationZ越大,说明他的层级越高
所以position = -1的view的层级就比position=0的view的层级低,
那么position=0的view就会叠在position=-1的view的上面,
除中间位置以外,其他子项,都设置低一些,这样才能突出中间子项
*/
view.setTranslationZ(position);
//按照子项宽度进行和位置进行平移,这样才能折叠到一起
view.setTranslationX((-pageWidth * 0.9f * position));
//除中间位置显示正常布局以外,其他布局,使用纯色背景,并且设置透明度显示
view.findViewById(R.id.ll_info).setVisibility(View.INVISIBLE);
view.findViewById(R.id.ll_zhegai).setVisibility(View.VISIBLE);
}
else if (position < 1)
{ // [-1,1]
// Modify the default slide transition to shrink the page as well
float vertMargin = pageHeight * (1 - scaleFactor) / 2;
float horzMargin = pageWidth * (1 - scaleFactor) / 2;
//中间位置透明度
if (position == 0)
{
view.setAlpha(1);
}
else
{
//中间位置滑动到两侧过程中,透明度变化
view.setAlpha(MIN_ALPHA + (scaleFactor - MIN_SCALE) / (1 - MIN_SCALE) * (1 - MIN_ALPHA));
}
view.findViewById(R.id.ll_info).setVisibility(View.VISIBLE);
view.findViewById(R.id.ll_zhegai).setVisibility(View.INVISIBLE);
if (position != 0)
{
view.setTranslationX((-pageWidth * 0.9f * position));
}
if (position > 0)
{
view.setTranslationZ(-position);
}
else
{
view.setTranslationZ(position);
}
if (position != 0)
{
//除中间位置不缩放以外,滑动到其他地方都缩放
view.setScaleX(scaleFactor);
view.setScaleY(scaleFactor);
}
// Fade the page relative to its size.
// view.setAlpha(MIN_ALPHA + (scaleFactor - MIN_SCALE) / (1 - MIN_SCALE) * (1 - MIN_ALPHA));
}
else if (position >= 1 && position <= 2)
{
view.setAlpha(0.1f);
// view.setAlpha((MIN_ALPHA + (scaleFactor - MIN_SCALE) / (1 - MIN_SCALE) * (1 - MIN_ALPHA))*0.5f);
if (position > 1 && position <= 2)
{
view.setScaleX(scaleFactor * 0.9f);
view.setScaleY(scaleFactor * 0.9f);
}
else
{
view.setScaleX(scaleFactor);
view.setScaleY(scaleFactor);
}
/**
这个translationZ设置view的层级,translationZ越大,说明他的层级越高
所以position = -1的view的层级就比position=0的view的层级低,那么position=0的view就会叠在
position=-1的view的上面,除中间位置以外,其他子项,都设置低一些,这样才能突出中间子项
*/
view.setTranslationZ(-position);
//按照子项宽度进行和位置进行平移,这样才能折叠到一起
view.setTranslationX((-pageWidth * 0.9f * position));
//除中间位置显示正常布局以外,其他布局,使用纯色背景,并且设置透明度显示
view.findViewById(R.id.ll_info).setVisibility(View.INVISIBLE);
view.findViewById(R.id.ll_zhegai).setVisibility(View.VISIBLE);
}
else
{ //右侧第二个子项以外,设置透明度为0,不可见
view.setAlpha(0);
view.setScaleX(defaultScale);
view.setScaleY(defaultScale);
view.setTranslationZ(-position);
}
}
}
ViewPager每次notifyDataSetChanged之后,所设置的PageTransformer显示就出问题?