您的位置:首页 > 移动开发 > Android开发

Android框架之路——Banner实现轮播图(RecyclerView添加Header)

2017-09-08 14:12 495 查看


一、简介

Banner能实现循环播放多个广告图片和手动滑动循环等功能。因为原生ViewPager并不支持循环翻页, 要实现循环还得需要自己去动手。Banner框架可以进行不同样式、不同动画设置, 以及完善的api方法能满足大部分软件首页轮播图效果的需求。

有一篇博客讲了一些,可以参考banner框架,一个比较齐全的框架;

此项目的Github地址:链接

本篇教程依然涉及一些其他方面的东西,如果有问题,可以参考我之前的系列文章。


二、添加依赖

build.gradle中添加依赖:
dependencies{
compile 'com.youth.banner:banner:1.4.9'  //最新版本
}


添加权限:
<!-- if you want to load images from the internet -->
<uses-permission android:name="android.permission.INTERNET" />

<!-- if you want to load images from a file OR from the internet -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />



三、解锁技能

1. 加载数据和刷新数据:

首先,添加我们MainActivity的布局文件,里面含有一个SwipeRefreshLayout,包裹RecyclerView,SwipeRefreshLayout用来实现下拉刷新。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:context="com.ping.bannerdemo.activity.MainActivity">

<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/swipeRefreshLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content">

<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content">

</android.support.v7.widget.RecyclerView>

</android.support.v4.widget.SwipeRefreshLayout>

</LinearLayout>


然后,我们要在RecyclerView中添加俩种布局,一个Header存放Banner,另一个则是正常的item布局。先放上俩个布局的内容。
//header.xml
<?xml version="1.0" encoding="utf-8"?>
<com.youth.banner.Banner
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/banner"
android:layout_width="match_parent"
android:layout_height="match_parent"/>

//item_recycler.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:padding="5dp"
android:gravity="center"
android:id="@+id/tv_item"
android:textSize="20dp"
android:textColor="#000"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>

</LinearLayout>


要添加俩种布局,得在Adapter中实现,这里可以全面的看一下各种LayoutManager中怎么添加header布局,戳这。这里,我就用了文中的第一个,主要方法就是根据不同的ViewType返回不同的ViewHolder。通过setter方法将header的view注入进adapter。先来看一下adapter吧。
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {

public static final int TYPE_HEADER = 0;
public static final int TYPE_NORMAL = 1;

private View mHeaderView;
private String[] mData;
private Context mContext;

public void setHeaderView(View headerView) {
mHeaderView = headerView;
}

public MyAdapter(Context context, String[] data) {
mContext = context;
mData = data;
}

//根据pos返回不同的ItemViewType
@Override
public int getItemViewType(int position) {
if (mHeaderView == null) return TYPE_NORMAL;
if (position == 0) return TYPE_HEADER;
return TYPE_NORMAL;
}

//在此根据ItemViewType来决定返回何种ViewHolder
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (mHeaderView != null && viewType == TYPE_HEADER)
return new MyViewHolder(mHeaderView);
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_recycler, parent, false);
return new MyViewHolder(view);
}

@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
if(getItemViewType(position) == TYPE_HEADER) return;

final int pos = getRealPosition(holder);
final String data = mData[pos];
if(holder instanceof MyViewHolder) {
((MyViewHolder) holder).mTvItem.setText(data);
}
}

private int getRealPosition(RecyclerView.ViewHolder holder) {
int position = holder.getLayoutPosition();
return mHeaderView == null ? position : position - 1;
}

//返回正确的item个数
@Override
public int getItemCount() {
return mHeaderView == null ? mData.length : mData.length + 1;
}

public class MyViewHolder extends RecyclerView.ViewHolder {

@BindView(R.id.tv_item)
TextView mTvItem;

public MyViewHolder(View itemView) {
super(itemView);
if(itemView == mHeaderView)
return;
ButterKnife.bind(this, itemView);
}
}
}


看完Adapter,我们要看看在哪里对headerview进行set了。MainActivity中我们渲染出header的布局,然后通过setHeaderView将view传递进去即可。
//渲染header布局
View header = LayoutInflater.from(this).inflate(R.layout.header
f1db
, null);
mBanner = (Banner) header.findViewById(R.id.banner);
//设置banner的高度为手机屏幕的四分之一
mBanner.setLayoutParams(new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, App.H/4));
//arrays资源文件存放banner图片的url地址
String[] data = getResources().getStringArray(R.array.demo_list);

mRecyclerView.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
myAdapter = new MyAdapter(this, data);
//设置headerview
myAdapter.setHeaderView(mBanner);
mRecyclerView.setAdapter(myAdapter);


然而启动banner:
mBanner.setImages(App.images)
.setImageLoader(new GlideImageLoader())
.start();


这里new了一个GlideImageLoader的实例,官方给出的各种图片加载库加载的方式如下:
public class GlideImageLoader extends ImageLoader {
@Override
public void displayImage(Context context, Object path, ImageView imageView) {
/**
注意:
1.图片加载器由自己选择,这里不限制,只是提供几种使用方法
2.返回的图片路径为Object类型,由于不能确定你到底使用的那种图片加载器,
传输的到的是什么格式,那么这种就使用Object接收和返回,你只需要强转成你传输的类型就行,
切记不要胡乱强转!
*/
eg:

//Glide 加载图片简单用法
Glide.with(context).load(path).into(imageView);

//Picasso 加载图片简单用法
Picasso.with(context).load(path).into(imageView);

//用fresco加载图片简单用法,记得要写下面的createImageView方法
Uri uri = Uri.parse((String) path);
imageView.setImageURI(uri);
}

//提供createImageView 方法,如果不用可以不重写这个方法,主要是方便自定义ImageView的创建
@Override
public ImageView createImageView(Context context) {
//使用fresco,需要创建它提供的ImageView,当然你也可以用自己自定义的具有图片加载功能的ImageView
SimpleDraweeView simpleDraweeView=new SimpleDraweeView(context);
return simpleDraweeView;
}
}


下拉时,我们需要在轮播图中更新数据,我们需要为SwipeRefreshLayout添加onRefresh()事件:
private Handler mHandler = new Handler() {
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case REFRESH_COMPLETE:
String[] urls = getResources().getStringArray(R.array.url);
List list = Arrays.asList(urls);
List arrayList = new ArrayList(list);
//把新的图片地址加载到Banner
mBanner.update(arrayList);
//下拉刷新控件隐藏
mSwipeRefreshLayout.setRefreshing(false);
break;
}
}
};

.......

mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
mHandler.sendEmptyMessageDelayed(REFRESH_COMPLETE, 2000);
}
});


在Banner中,我们设置了高度为四分之一屏幕,屏幕的高度是在app一初始化就获取到的,同时,在这里我们用了一个Android Crash的框架Recovery,也没必要用,就是可以把错误反馈到手机上。可以参考这个博客。
public class App extends Application{

public static int H;
public static List<?> images=new ArrayList<>();
public static List<String> titles=new ArrayList<>();

@Override
public void onCreate() {
super.onCreate();

initBanner();
}

private void initBanner() {
H = getScreenH(this);

Recovery.getInstance()
.debug(true)
.recoverInBackground(false)
.recoverStack(true)
.mainPage(MainActivity.class)
.init(this);

String[] urls = getResources().getStringArray(R.array.url4);
String[] tips = getResources().getStringArray(R.array.title);
List list = Arrays.asList(urls);
images = new ArrayList<>(list);
titles= Arrays.asList(tips);
}

/**
* 获取屏幕高度
* @param aty
* @return
*/
public int getScreenH(Context aty){
DisplayMetrics dm = aty.getResources().getDisplayMetrics();
return dm.heightPixels;
}
}


最后,看一下我们的运行效果: 



2. Banner的各种动画:

Banner的动画都在com.youth.banner.transformer包下,包含下面的这些,相信看名字就知道大概什么效果。
com.youth.banner.transformer.AccordionTransformer;
com.youth.banner.transformer.BackgroundToForegroundTransformer;
com.youth.banner.transformer.CubeInTransformer;
com.youth.banner.transformer.CubeOutTransformer;
com.youth.banner.transformer.DefaultTransformer;
com.youth.banner.transformer.DepthPageTransformer;
com.youth.banner.transformer.FlipHorizontalTransformer;
com.youth.banner.transformer.FlipVerticalTransformer;
com.youth.banner.transformer.ForegroundToBackgroundTransformer;
com.youth.banner.transformer.RotateDownTransformer;
com.youth.banner.transformer.RotateUpTransformer;
com.youth.banner.transformer.ScaleInOutTransformer;
com.youth.banner.transformer.StackTransformer;
com.youth.banner.transformer.TabletTransformer;
com.youth.banner.transformer.ZoomInTransformer;
com.youth.banner.transformer.ZoomOutSlideTransformer;
com.youth.banner.transformer.ZoomOutTranformer;


通过setBannerAnimation()来设置动画。例如,设置为方块滚动;
......

mBanner.setImages(App.images)
.setBannerAnimation(CubeOutTransformer.class)
.setImageLoader(new GlideImageLoader())
.start();

......


效果如下: 



3. Banner的各种内置样式 :

Banner内置的样式有以下几种,
BannerConfig.NOT_INDICATOR       //没有指示器
BannerConfig.CIRCLE_INDICATOR    //圆圈指示器(默认)
BannerConfig.NUM_INDICATOR       //数字圆盘指示器
BannerConfig.NUM_INDICATOR_TITLE //数字圆盘带标题的
BannerConfig.CIRCLE_INDICATOR_TITLE  //圆圈指示器附带标题
BannerConfig.CIRCLE_INDICATOR_TITLE_INSIDE  //区别于上一个,圆圈指示器在标题栏里


这里我们实现一下圆圈指示器附带标题的样式:
ArrayList<String> titles = new ArrayList<>(Arrays.asList(new String[]{"first title", "second title", "third title", "fourth title"}));
mBanner.setImages(App.images)
.setBannerAnimation(CubeOutTransformer.class)
.setBannerStyle(BannerConfig.CIRCLE_INDICATOR_TITLE)
.setBannerTitles(titles)
.setImageLoader(new GlideImageLoader())
.start();


效果如下: 



4. Banner自定义样式:

自定义banner的属性:
Attributesformadescribe
delay_timeinteger轮播间隔时间,默认2000
scroll_timeinteger轮播滑动执行时间,默认800
is_auto_playboolean是否自动轮播,默认true
title_backgroundcolorreference
title_textcolorcolor标题字体颜色
title_textsizedimension标题字体大小
title_heightdimension标题栏高度
indicator_widthdimension指示器圆形按钮的宽度
indicator_heightdimension指示器圆形按钮的高度
indicator_margindimension指示器之间的间距
indicator_drawable_selectedreference指示器选中效果
indicator_drawable_unselectedreference指示器未选中效果
image_scale_typeenum和imageview的ScaleType作用一样
参照上述属性,现在对指示器设置高宽和选中颜色:
<com.youth.banner.Banner
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/banner"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:indicator_drawable_selected="@color/colorAccent"
app:indicator_drawable_unselected="@android:color/white"
app:indicator_height="4dp"
app:indicator_margin="4dp"
app:indicator_width="20dp"/>


实现效果: 




四、Demo下载:

     
 下载链接
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Banner 轮播