好吧,最近收到了一波蛇皮风格的banner效果,先看图 ,大概就是中间banner会露出来两边,然后支持无限轮播。
首先看到这个效果肯定会想到采用viewpager来实现,但是viewpager一个item的宽度基本上都是占了一个屏幕。所以这里就涉及到了一个属性 clipChildren,这个属性的作用就是控制他的子控件是否要在他应有的边界内进行绘制,默认是为true,也就是不允许,所以这里我们要设置为false。这个属性在很多地方都有用到过,适用于各种凸出来的view。
接下来上Xml代码
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:clipChildren="false"
android:layerType="software"
android:orientation="vertical"
>
<android.support.v4.view.ViewPager
android:id="@+id/mvp"
android:layout_width="match_parent"
android:layout_height="200dp"
android:clipChildren="false"
android:layerType="software"
/>
LinearLayout>
然后接下来我们就要封装一个适配器了,主要是为了实现无限循环播放
public abstract class BaseAdapter<T> extends PagerAdapter implements ViewPager.OnPageChangeListener{
//当前页面
private int currentPosition = 0;
protected Context mContext;
protected ArrayList views;
protected ViewPager mViewPager;
public BaseAdapter(Context context, List datas, ViewPager viewPager) {
mContext = context;
views = new ArrayList<>();
//如果数据大于一条
if(datas.size() > 1) {
//添加最后一页到第一页
datas.add(0,datas.get(datas.size()-1));
//添加第一页(经过上行的添加已经是第二页了)到最后一页
datas.add(datas.get(1));
}
for (T data:datas) {
views.add(getItemView(data));
}
mViewPager = viewPager;
viewPager.setAdapter(this);
viewPager.addOnPageChangeListener(this);
viewPager.setCurrentItem(1,false);
}
@Override
public int getCount() {
return views.size();
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
View v =views.get(position);
ViewGroup parent = (ViewGroup) v.getParent();
if (parent != null) {
parent.removeAllViews();
}
container.addView(views.get(position));
return views.get(position);
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView(views.get(position));
}
protected abstract View getItemView(T data);
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
currentPosition = position;
}
@Override
public void onPageScrollStateChanged(int state) {
//若viewpager滑动未停止,直接返回
if (state != ViewPager.SCROLL_STATE_IDLE) return;
//若当前为第一张,设置页面为倒数第二张
if (currentPosition == 0) {
mViewPager.setCurrentItem(views.size()-2,false);
} else if (currentPosition == views.size()-1) {
//若当前为倒数第一张,设置页面为第二张
mViewPager.setCurrentItem(1,false);
}
}
}
这是一个抽象的adapter,主要对滑动后做一些处理,通过这样来实现无限循环播放,使用泛型的目的是为了适应各种数据,因为考虑到我们的banner可能不单纯是一个imageview,还有其他一些东西。
接下来我们要实现这个适配器
public class HeadAdapter extends BaseAdapter {
public HeadAdapter(Context context, List datas, ViewPager viewPager) {
super(context, datas, viewPager);
}
private ViewGroup.LayoutParams layoutParams;
@Override
protected View getItemView(Integer data) {
if (layoutParams == null) {
layoutParams = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
}
View view= LayoutInflater.from(mContext).inflate(R.layout.item_layout,null);
ImageView i =view.findViewById(R.id.item_image1);
i.setScaleType(ImageView.ScaleType.CENTER_CROP);
i.setImageResource(data);
return view;
}
}
这个代码就很简单了,就是设置item了,这里我是直接用的资源文件图片,所以传的Integer。
好了,接下来就是怎么使用了
public class TestActivity extends AppCompatActivity {
private ViewPager mPager;
HeadAdapter loopVPAdapter;
private Handler mHandler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
mPager=findViewById(R.id.mvp);
mPager.setClipToPadding(false);
// set padding manually, the more you set the padding the more you see of prev & next page
mPager.setPadding(50, 0, 50, 0);
// sets a margin b/w individual pages to ensure that there is a gap b/w them
mPager.setPageMargin(10);
ArrayList urls=new ArrayList<>();
urls.add(R.mipmap.img1);
urls.add(R.mipmap.img2);
urls.add(R.mipmap.img3);
loopVPAdapter=new HeadAdapter(getApplicationContext(), urls,mPager);
mHandler=new Handler();
mHandler.postDelayed(new TestActivity.TimerRunnable(), 3000);
ViewPagerScroller scroller = new ViewPagerScroller(TestActivity.this);
scroller.setScrollDuration(1500);
scroller.initViewPagerScroll(mPager);//这个是设置切换过渡时间为2秒
}
class TimerRunnable implements Runnable{
@Override
public void run() {
int curItem = mPager.getCurrentItem();
mPager.setCurrentItem(curItem+1);
if (mHandler!=null){
mHandler.postDelayed(this,3000);
}
}
}
}
这里我们要设置一下间隔了,间隔大小我们可以随意控制,然后 ViewPagerScroller这个东西是用来控制滚动速度的,如果没有需求可以不用管,就用默认的速度,最后我们就开启一个轮询 3秒钟滚动一次,到这里蛇皮banner无限滚动就差不多完成了。
最后还说一下banner的阴影,之前有使用了cardview发现并没有什么卵用,可能可以绘制有关,所以最后考虑到了使用一个第三方库来实现这个阴影。
implementation ‘com.github.dmytrodanylyk.shadow-layout:library:1.0.3’
最后附上项目链接