android 新闻轮播,]Android 仿网易新闻 ViewPager 实现图片自动轮播

前言

新闻 App 首页最上方一般会循环播放热点图片,如下图所示。

94735153_1.png

本文主要介绍了利用 ViewPager 实现轮播图片,图片下方加上小圆点指示器标记当前位置,并利用 Timer+Handler 实现了自动轮播播放。

xml 布局

FrameLayout里面包含了ViewPager和LinearLayout,ViewPager 显示图片,LinearLayout是小圆点指示器区域,标记现在滑到哪张图片。

查看 xml 预览图,由于没有图片内容,当前只显示出红色矩形区域。

94735153_2.png

新建javabean

首页的图片地址是新闻的一个属性,我们新建一个ItemArticle类。

public class ItemArticle {

// 新闻的 id

private int index;

// 新闻里的图片 url

private String imageUrl;

public ItemArticle(int index, String imageUrl) {

this.index = index;

this.imageUrl = imageUrl;

}

public int getIndex() {

return index;

}

public void setIndex(int index) {

this.index = index;

}

public String getImageUrl() {

return imageUrl;

}

public void setImageUrl(String imageUrl) {

this.imageUrl = imageUrl;

}

}

适配器 PagerAdapter

继承自 android.support.v4.view.PagerAdapter,复写4个方法

instantiateItem(ViewGroup, int)

destroyItem(ViewGroup, int, Object)

getCount()

isViewFromObject(View, Object)

public class HeaderAdapter extends PagerAdapter {

private static final String LOG = "NEWS_LOG";

private Activity context;

private List articles;

private List images = new ArrayList();

public HeaderAdapter(Activity context, List articles) {

this.context = context;

if (articles == null || articles.size() == 0) {

this.articles = new ArrayList<>();

} else {

this.articles = articles;

}

for (int i = 0; i < articles.size(); i++) {

SimpleDraweeView image = new SimpleDraweeView(context);

Uri uri = Uri.parse(articles.get(i).getImageUrl());

image.setImageURI(uri);

images.add(image);

}

}

@Override

public Object instantiateItem(ViewGroup container, int position) {

container.addView(images.get(position));

return images.get(position);

}

@Override

public void destroyItem(ViewGroup container, int position, Object object) {

container.removeView(images.get(position));

}

@Override

public int getCount() {

return articles.size();

}

@Override

public boolean isViewFromObject(View view, Object object) {

Log.i(LOG, "in isViewFromObject view: " + view + " object: "

+ object + " equal: " + (view == (View) object));

return view == (View) object;

}

}

深入解析 isViewFromObject 方法

isViewFromObject(View view, Object object)的通用写法是return view == (View) object;

其中(View) object可根据具体情形替换成LinearLayout等等。

查看 ViewPager 源代码(戳这里)

isViewFromObject是在infoForChild里被调用的,而且在该方法内会被调用mItems.size()次,mItems.size()是 ViewPager 里面图片的个数。

static class ItemInfo {

Object object;

int position;

boolean scrolling;

}

private final ArrayList mItems = new ArrayList();

ItemInfo infoForChild(View child) {

for (int i=0; i

ItemInfo ii = mItems.get(i);

if (mAdapter.isViewFromObject(child, ii.object)) {

return ii;

}

}

return null;

}

ViewPager里面用了一个mItems 存储每个page的信息(ItemInfo),当界面要展示或者发生变化时,需要依据page的当前信息来调整,但此时只能通过view来查找,遍历mItems通过比较view和object来找到对应的ItemInfo。

Log.i(LOG, "in isViewFromObject view: " + view + " object: "

+ object + " equal: " + (view == (View) object));

所以我们如果打印出 Log 的话,会看到isViewFromObject()被调用多次,只有1次返回 true (表示找到了对应的ItemInfo),其他返回 false。

01-17 10:15:21.207 I/NEWS_LOG﹕ in isViewFromObject

view: SimpleDraweeView{holder=DraweeHolder{...}

object: SimpleDraweeView{holder=DraweeHolder{...}

equal: false

01-17 10:15:21.207 I/NEWS_LOG﹕ in isViewFromObject

view: SimpleDraweeView{holder=DraweeHolder{...}

object: SimpleDraweeView{holder=DraweeHolder{...}

equal: false

01-17 10:15:21.207 I/NEWS_LOG﹕ in isViewFromObject

view: SimpleDraweeView{holder=DraweeHolder{...}

object: SimpleDraweeView{holder=DraweeHolder{...}

equal: false

01-17 10:15:21.207 I/NEWS_LOG﹕ in isViewFromObject

view: SimpleDraweeView{holder=DraweeHolder{...}

object: SimpleDraweeView{....}}

equal: true

增加底部小圆点指示器

轮播图片的底部都会加上小圆点,指示当前访问图片的位置。

94735153_3.png

private ImageView[] mBottomImages;//底部只是当前页面的小圆点

//创建底部指示位置的导航栏

mBottomImages = new ImageView[headerArticles.size()];

for (int i = 0; i < mBottomImages.length; i++) {

ImageView imageView = new ImageView(mAct);

LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(10, 10);

params.setMargins(5, 0, 5, 0);

imageView.setLayoutParams(params);

if (i == 0) {

imageView.setBackgroundResource(R.drawable.indicator_select);

} else {

imageView.setBackgroundResource(R.drawable.indicator_not_select);

}

mBottomImages[i] = imageView;

//把指示作用的原点图片加入底部的视图中

llHottestIndicator.addView(mBottomImages[i]);

}

上面这段代码是小圆点的初始步骤,最开始是第0张图片被选中,所以是第0张小圆点是蓝色,其他小圆点是灰色。

addOnPageChangeListener 使得小圆点动态变化

切换图片的时候,小圆点也要随着改变,这需要利用ViewPager.OnPageChangeListener,主要是下面这个方法:

public abstract void onPageSelected (int position)

This method will be invoked when a new page becomes selected. Animation is not necessarily complete.

Parameters

position Position index of the new selected page.

vpHottest.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {

//图片左右滑动时候,将当前页的圆点图片设为选中状态

@Override

public void onPageSelected(int position) {

// 一定几个图片,几个圆点,但注意是从0开始的

int total = mBottomImages.length;

for (int j = 0; j < total; j++) {

if (j == position) {

mBottomImages[j].setBackgroundResource(R.drawable.indicator_select);

} else {

mBottomImages[j].setBackgroundResource(R.drawable.indicator_not_select);

}

}

}

@Override

public void onPageScrolled(int i, float v, int i1) {

}

@Override

public void onPageScrollStateChanged(int state) {

}

});

onPageSelected()中,利用 for 循环,将当前选中位置对应的小圆点置为蓝色,其他小圆点置为灰色。

自动播放

先定义一个 Handler,在主线程里面更新 UI

//定时轮播图片,需要在主线程里面修改 UI

private Handler mHandler = new Handler() {

public void handleMessage(Message msg) {

switch (msg.what) {

case UPTATE_VIEWPAGER:

if (msg.arg1 != 0) {

vpHottest.setCurrentItem(msg.arg1);

} else {

//false 当从末页调到首页是,不显示翻页动画效果,

vpHottest.setCurrentItem(msg.arg1, false);

}

break;

}

}

};

利用 Timer 实现每隔 5s 向 Handler 发送message来更新图片

// 设置自动轮播图片,5s后执行,周期是5s

timer.schedule(new TimerTask() {

@Override

public void run() {

Message message = new Message();

message.what = UPTATE_VIEWPAGER;

if (autoCurrIndex == headerArticles.size() - 1) {

autoCurrIndex = -1;

}

message.arg1 = autoCurrIndex + 1;

mHandler.sendMessage(message);

}

}, 5000, 5000);

为了使得滑到最后一页后能滑到首页,我们对于autoCurrIndex == headerArticles.size() - 1进行了处理。

完整代码

基于上面的分析,我们实现了自动轮播图片

94735153_4.png

public class MasterArticleFragment extends Fragment {

private static final String ARTICLE_LATEST_PARAM = "param";

private static final int UPTATE_VIEWPAGER = 0;

//轮播的最热新闻图片

@InjectView(R.id.vp_hottest)

ViewPager vpHottest;

//轮播图片下面的小圆点

@InjectView(R.id.ll_hottest_indicator)

LinearLayout llHottestIndicator;

//存储的参数

private String mParam;

//获取 fragment 依赖的 Activity,方便使用 Context

private Activity mAct;

//设置当前 第几个图片 被选中

private int autoCurrIndex = 0;

private ImageView[] mBottomImages;//底部只是当前页面的小圆点

private Timer timer = new Timer(); //为了方便取消定时轮播,将 Timer 设为全局

//定时轮播图片,需要在主线程里面修改 UI

private Handler mHandler = new Handler() {

public void handleMessage(Message msg) {

switch (msg.what) {

case UPTATE_VIEWPAGER:

if (msg.arg1 != 0) {

vpHottest.setCurrentItem(msg.arg1);

} else {

//false 当从末页调到首页是,不显示翻页动画效果,

vpHottest.setCurrentItem(msg.arg1, false);

}

break;

}

}

};

public static MasterArticleFragment newInstance(String param) {

MasterArticleFragment fragment = new MasterArticleFragment();

Bundle args = new Bundle();

args.putString(ARTICLE_LATEST_PARAM, param);

fragment.setArguments(args);

return fragment;

}

@Override

public void onCreate(@Nullable Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

if (savedInstanceState != null) {

mParam = savedInstanceState.getString(ARTICLE_LATEST_PARAM);

}

}

@Nullable

@Override

public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

View view = inflater.inflate(R.layout.fragment_one_master, container, false);

mAct = getActivity();

ButterKnife.inject(this, view);

return view;

}

@Override

public void onActivityCreated(@Nullable Bundle savedInstanceState) {

super.onActivityCreated(savedInstanceState);

new ImageTask().execute();

}

@Override

public void onDestroyView() {

super.onDestroyView();

ButterKnife.reset(this);

}

private void setUpViewPager(final List headerArticles) {

HeaderAdapter imageAdapter = new HeaderAdapter(mAct, headerArticles);

vpHottest.setAdapter(imageAdapter);

//创建底部指示位置的导航栏

mBottomImages = new ImageView[headerArticles.size()];

for (int i = 0; i < mBottomImages.length; i++) {

ImageView imageView = new ImageView(mAct);

LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(10, 10);

params.setMargins(5, 0, 5, 0);

imageView.setLayoutParams(params);

if (i == 0) {

imageView.setBackgroundResource(R.drawable.indicator_select);

} else {

imageView.setBackgroundResource(R.drawable.indicator_not_select);

}

mBottomImages[i] = imageView;

//把指示作用的原点图片加入底部的视图中

llHottestIndicator.addView(mBottomImages[i]);

}

vpHottest.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {

//图片左右滑动时候,将当前页的圆点图片设为选中状态

@Override

public void onPageSelected(int position) {

// 一定几个图片,几个圆点,但注意是从0开始的

int total = mBottomImages.length;

for (int j = 0; j < total; j++) {

if (j == position) {

mBottomImages[j].setBackgroundResource(R.drawable.indicator_select);

} else {

mBottomImages[j].setBackgroundResource(R.drawable.indicator_not_select);

}

}

//设置全局变量,currentIndex为选中图标的 index

autoCurrIndex = position;

}

@Override

public void onPageScrolled(int i, float v, int i1) {

}

@Override

public void onPageScrollStateChanged(int state) {

}

}

);

// 设置自动轮播图片,5s后执行,周期是5s

timer.schedule(new TimerTask() {

@Override

public void run() {

Message message = new Message();

message.what = UPTATE_VIEWPAGER;

if (autoCurrIndex == headerArticles.size() - 1) {

autoCurrIndex = -1;

}

message.arg1 = autoCurrIndex + 1;

mHandler.sendMessage(message);

}

}, 5000, 5000);

}

class ImageTask extends AsyncTask> {

@Override

protected List doInBackground(String... params) {

List articles = new ArrayList();

articles.add(

new ItemArticle(1123, "http://***20151231105648_11790.jpg"));

articles.add(

new ItemArticle(1123, "http://***20151230152544_36663.jpg"));

articles.add(

new ItemArticle(1123, "http://***20151229204329_75030.jpg"));

articles.add(

new ItemArticle(1123, "http://***20151221151031_36136.jpg"));

return articles;

}

@Override

protected void onPostExecute(List articles) {

//这儿的 是 url 的集合

super.onPostExecute(articles);

setUpViewPager(articles);

}

}

}

一些知识点

schedule和scheduleAtFixedRate方法

(1)schedule方法:下一次执行时间相对于 上一次 实际执行完成的时间点 ,因此执行时间会不断延后。保持间隔时间的稳定

(2)scheduleAtFixedRate方法:下一次执行时间相对于上一次开始的 时间点 ,因此执行时间不会延后,存在并发性 。保持执行频率的稳定。

参考文章

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值