[Android]使用ViewPager实现图片滑动展示
在淘宝等电商的APP首页经常能看到大幅的广告位,通常有多幅经常更新的图片用于展示促销信息,如下图所示:
通常会自动滚动,也可以根据手势滑动。我没有研究过人家的APP是通过什么实现的,可能有第三方已经封装好的控件可以直接使用,也可能通过webview来实现,毕竟在网页上也有很多类似的内容。如果有高手经验丰富不妨指点一二。不管别人怎样,今天我准备自己动手做一个,其实也不是特别复杂的。
我主要使用的实现方法是Android自带的ViewPager控件,这个控件主要用于实现屏幕水平切换,有自带的动画效果。Android官网上有使用教程:http://developer.android.com/training/animation/screen-slide.html,当然下文会有相一致的说明。
然后就开始动手实现这个图片滑动效果吧。
1. 首先解释一下ViewPager的使用过程,通常来说ViewPager可以和Fragment结合起来用,每次ViewPager滑动,也就是展示一个新的Fragment。Fragment里面就是我们需要展现的内容。而这滑动的动画就交给ViewPager来实现。所以第一步我们需要设置好Fragment的内容,新建一个布局文件,这里只需要展示一张图即可,当然可以根据自己的需要进行改变:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" > <ImageView
android:id="@+id/iv_main_pic"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="@string/main_image"
android:scaleType="fitXY" /> </RelativeLayout>
2. 然后建立Fragment类。
import android.support.v4.app.Fragment;
...... public class PictureSlideFragment extends Fragment { @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) { View v = inflater.inflate(R.layout.fragment_picture_slide, container, false); return v;
} }
3. 在Activity布局文件的合适位置加入ViewPager控件。
<android.support.v4.view.ViewPager
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
4. 在Activity中得到这个ViewPager并且为其设置Adapter:
private ViewPager mPager; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mPager = (ViewPager) findViewById(R.id.pager);
mPagerAdapter = new PictureSlidePagerAdapter(getSupportFragmentManager());
mPager.setAdapter(mPagerAdapter);
}
5. 这个Adapter继承自FragmentStatePagerAdapter,其中getCount()返回的值是一共需要显示的内容数,是个常数:
private class PictureSlidePagerAdapter extends FragmentStatePagerAdapter { public PictureSlidePagerAdapter(FragmentManager fm) {
super(fm);
// TODO Auto-generated constructor stub
} @Override
public Fragment getItem(int arg0) {
// TODO Auto-generated method stub
return new PictureSlideFragment();
} @Override
public int getCount() {
// TODO Auto-generated method stub
return NUM_PIC;
}
}
6. 到目前为止所有的内容都和官方的教程一致。如果你在Fragment中的那个ImageView通过android:src属性设置图片,会实现数张静态图片滑动的效果。这离我们的目标还有一些区别:
(1)图片需要能够动态改变,而不是固定的内容;
(2)每张图片需要有点击的响应;
(3)一般情况下需要实现循环滚动,即滑到最后一张图时继续滑动会回到第一张图;
(4)图片要能够自动滚动;
(5)图片下方需要有显示第几张图的指示(小圆点)。
7. 接下来我们朝着目标继续努力。首先是图片的变化。观察上述Adapter的实现方法,可以发现getItem()方法每次返回的都是一个Fragment的实例,需要显示多少个Fragment这个方法就会执行多少遍。但我们发现每次创建新的Fragment都没有区别,直接new一个了事,因此我们需要改写这个创建新Fragment实例的方法,以实现每次新建的Fragment实例都不一样。在我们的Fragment类中补充如下内容:
private int mIndex; public static PictureSlideFragment newInstance(int index) {
PictureSlideFragment f = new PictureSlideFragment(); Bundle args = new Bundle();
args.putInt("index", index);
f.setArguments(args); return f;
} @Override
public void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
mIndex = getArguments() != null ? getArguments().getInt("index") : 1; }
这个叫做newInstance的方法主要功能也是创建一个Fragment实例,和直接new的区别是传递进来一个index参数,这个参数在onCreate()方法中被获得。然后我们将Adapter的getItem()改写为如下:
@Override
public Fragment getItem(int arg0) {
// TODO Auto-generated method stub
return PictureSlideFragment.newInstance(arg0);
}
每次getItem都将Item的序号传递到新建的Fragment,然后再Fragment中根据需要设定不同的内容。真正实现的时候,可以在Fragment中加入从网络获取图片的操作。
8. 图片的点击响应。这个比较简单,在Fragment中获得ImageView控件,然后设置onClick监听器即可。就不给出代码了。
9. 图片的循环滚动。一般的ViewPager不能实现内容的循环滚动,即第一张向左滑或者最后一张向右滑都会到顶,显示到顶的效果。如果要从ViewPager自身入手加入这功能需要对这个控件进行改写,比较麻烦,这里我从stackoverflow上找到了一种比较聪明的办法。
要实现几张图的循环滚动,其实只需要满足视觉效果就可以了。比如有三张图A,B,C,要实现A->B->C->A->B......以及C->B->A->C->B...这样的循环,实际上可以这样实现:
提供5张图,分别是C' A B C A',其中C'和C,A'和A完全相同,当滑到C'时,自动切换到C,当滑到A'时,自动切换到A,并且这个切换过程没有动画,于是,使用者体验出来的感觉就是A B C三张图在循环滚动了。
于是我们为ViewPager添加setOnPageChangeListener方法:
mPager.setOnPageChangeListener(new OnPageChangeListener() { @Override
public void onPageSelected(int arg0) {
// TODO Auto-generated method stub } @Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
// TODO Auto-generated method stub } @Override
public void onPageScrollStateChanged(int state) {
// 当到第一张时切换到倒数第二张,当到最后一张时切换到第二张
if (state == ViewPager.SCROLL_STATE_IDLE) {
int curr = mPager.getCurrentItem();
int lastReal = mPager.getAdapter().getCount() - 2;
if (curr == 0) {
mPager.setCurrentItem(lastReal, false);
} else if (curr > lastReal) {
mPager.setCurrentItem(1, false);
}
}
}
});
覆写的onPageScrollStateChanged方法在滑动内容改变时调用,在其中实现C'和C,A'和A的切换。
10. 图片的自动滚动,这里我使用了timer启动线程来实现,定时器线程每隔5秒发送消息,UI线程捕获消息并调用ViewPager.setCurrentItem(currentItem+1, true)方法,滚动到下一张图片。代码就不赘述了。这里有个体验细节,就是当使用者用手指滑动时,定时器需要取消,防止自动滑动和手指滑动发生冲突。这个我在Fragment的ImageView的onTouchListener中实现:
mMainImage.setOnTouchListener(new OnTouchListener() { @Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
((MainActivity)getActivity()).getTimer().cancel();
} else if (event.getAction() == MotionEvent.ACTION_CANCEL) {
((MainActivity)getActivity()).startSwitchImage();
} return false;
}
});
11. 图片序号的指示,也就是图片下方的几个小圆点,这个实现比较简单,首先在Activity的布局文件中添加几个图片,因为这几个小圆点本身不能随ViewPager移动,因此不能放在Fragment布局中。切换内容也就是切换显示不同颜色小圆点的位置,这个方法同样可以在onPageScrollStateChanged方法中调用。注意一些细节,因为之前为了实现循环滚动而多用了两个Fragment,而显示的小圆点数量不能增加,因此需要调整好对应的序号。代码也不再赘述了。
最终的效果如下图所示,美食有木有。总结一下,整个过程并不复杂,就是一些细节需要仔细推敲。虽然做法可能有非主流的地方,但实现的效果跟别人的几乎完全一致,这样就行啦~
另外,这样的实现方法也不是完全没有值得改进的地方,比如图片自动滚动的延时还不能自定义。ViewPager没有现成的方法用来自改变自动滚动延时,如果需要自定义,就要自己改写这个控件啦,有兴趣的可以研究一下~
[Android]使用ViewPager实现图片滑动展示的更多相关文章
- 循序渐进BootstrapVue,开发公司门户网站(4)--- 使用b-carousel-slide组件实现图片轮播以及vue-awesome-swiper实现图片滑动展示
在BootstrapVue组件库里面,提供了很多对Bootstrap同等类似的组件封装,其中图片轮播可以采用b-carousel-slide组件实现,而有一些小的图片,如客户/合作伙伴Logo或者友情 ...
- 114、Android禁止ViewPager的左右滑动
有时候在开发中会遇到一些“诡异”的要求,比如在ViewPager中嵌入ListView,或者再嵌入一个ViewPager,那么在滑动的时候就会造成被嵌入的XXView不能滑动了,那么现在就把最外层的V ...
- Android listview viewpager解决冲突 滑动
Android listview viewpager滑动 跳动 冲突解决 ListView中嵌套ViewPage有或者滑动手势冲突解决 在listview 上使用 addHeaderView 在第 ...
- Android禁止ViewPager的左右滑动
转载请注明出处:http://blog.csdn.net/allen315410/article/details/40744287 有时候在开发中会遇到一些"诡异"的要求,比方在V ...
- 011 Android TabLayout+ViewPager实现顶部滑动效果(多个页面)
1.TabLayout介绍 TabLayout提供了一个水平的布局用来展示Tabs,很多应用都有这样的设计,典型的有网易新闻,简书,知乎等.TabLayout就可以很好的完成这一职责,首先TabLay ...
- 一个不错的图片滑动展示插件 anythingslider
一个不错的图片http://css-tricks.com/anythingslider-jquery-plugin/ DEMO演示: http://css-tricks.github.io/Anyth ...
- 《JavaScript 实战》:实现图片幻滑动展示效果
滑动展示效果主要用在图片或信息的滑动展示,也可以设置一下做成简单的口风琴(Accordion)效果.这个其实就是以前写的图片滑动展示效果的改进版,那是我第一篇比较受关注的文章,是时候整理一下了. 有如 ...
- Android使用ViewFlipper实现左右滑动效果面
在我的博客中,上次是使用ViewPager实现左右滑动的效果的,请看文章:Android使用ViewPager实现左右滑动效果. 这次我来使用ViewFlipper实现这种效果,好了,先看看效果吧: ...
- Android 使用ViewPager结合PhotoView开源组件实现网络图片在线浏览功能
在实际的开发中,我们市场会遇到这样的情况:点击某图片,浏览某列表(某列表详情)中的所有图片数据,当然,这些图片是可以放大和缩小的,比如我们看下百度贴吧的浏览大图的效果: 链接 这种功能,在一些app ...
随机推荐
- 关于JS面向对象、设计模式、以及继承的问题总结
1.对象:JS中万物皆对象,它是一个泛指 类:对象的具体的细分 (物以类聚,人与群分.具有相同属性和方法的实例的一个集合总称) 实例:某一个类别中具体的一个事物 对象是一个抽象的概念,类似于我们的自然 ...
- Android 自己定义主菜单
本文介绍一个超简单的自己定义主菜单.效果例如以下: 原理:事实上就是对原生的Dialog的一个简单的封装.并加上显示和隐藏的动画效果.再给控件加上回调事件. TestDialog.java publi ...
- LoaderManager使用具体解释(一)---没有Loader之前的世界
来源: http://www.androiddesignpatterns.com/2012/07/loaders-and-loadermanager-background.html 感谢作者Alex ...
- [array] leetCode-11. Container With Most Water-Medium
leetCode-11. Container With Most Water-Medium descrition Given n non-negative integers a1, a2, ..., ...
- ocx 中使用CImage和CComPtr
#include <atlimage.h> using namespace ATL;
- [Immutable.js] Updating nested values with ImmutableJS
The key to being productive with Immutable JS is understanding how to update values that are nested. ...
- mycat 离散分片 -> 程序指定分区的分片
1.程序指定分区的分片 此规则是在运行阶段有应用自主决定路由到那个分片. 此方法为直接依据字符子串(必须是数字)计算分区号(由应用传递參数.显式指定分区号). 2,加入配置文件 在function.x ...
- ios开发之级联菜单(两个tableView实现)
一:在ios项目实际开发中经常会看到级联菜单的效果:如图:点击左侧菜单,右侧菜单刷新数据.此篇用两个tableView来实现如图效果: 二:代码: 1:构造数据模型:利用kvc快速构建数据模型 #im ...
- hibernate级联保存问题
异常:org.hibernate.TransientObjectException: object references an unsaved transient instance 解决方法: XML ...
- Android的事件分发
1. Touch事件和绘制事件的异同之处 Touch事件和绘制事件非常相似,都是由ViewRoot派发下来的,可是不同之处在绘制事件是由应用中的某个View发起请求,一层一层上传到ViewRoot.再 ...