安卓(Android)ViewPager+TabLayout实现图片轮播效果
2016-11-09 22:01
1281 查看
起因:
最近在做一个新闻APP,看到现在的新闻客户端顶端都有个热点新闻轮播。
思路:viewpager可以用来显示图片,并且可以提供滑动,15年(不知记错没)新出的TabLayout可以绑定ViewPager的Adapter来实现ViewPager与Tablayout的联动效果,比如qq的下面菜单栏,微信的菜单栏,都可以这样实现。而且我们可以通过两种方式来实现TabLayout的图片标题:
1.SpannableString 来实现图文混排,混排方法(传送门)。
2.使用自定义布局,布局中添加你想要显示的内容,然后调用tablayout中tab的setCustomView(View view)或者setCustomView(int R_id)方法来设置显示。
下面正题:
这里我使用第二种方法来实现,至于为什么用第二种(好吧其实是我使用第一种的时候遇到了一个不显示的bug,当然第二种也遇到了,后面会提及,后来就没改回第一种了,原理一样)源码在最后面有下载。
一。首先我们来准备图片:
没有选中的位置的提示图片:
选中了之后的位置的提示图片:
图片都可以使用ps制作,很简单。
二。然后我们来写轮播界面的布局(老规矩,先代码后解释):
(1)translationZ属性:为了让Tablayout显示在Viewpager的上方,不设置z值大于ViewPager的话,就显示不出来了。
(2)tabMode属性:为了不让tablayout滑动(在内容超出控件宽度的时候里面内容滑动从而造成显示上的逻辑错误)。
(3)tabMinWidth属性:
tabMaxWidth属性:设置tab的最小值和最大值,来控制每个tab的宽度(先立个Flag)。
三。现在我们来为ViewPager的内容写布局文件,这里我们的内容有新闻图片(覆盖全页面),新闻标题(位于左下角),
布局文件如下:
四。既然我们要自定义tablayout的布局,那么我们现在就来写这个布局文件
布局很简单,就一个ImageView,为了拉伸图片到全部页面,我们这里设置他的background属性而不是src属性:
五。布局我们已经弄好了,接下来就是逻辑代码了,我这里使用继承自Fragment是为了方便插入任何其他布局里,我这里插入的是首页。
这里插播一下布局中插入碎片(Fragment)的方法,老规矩:
注意上面的name属性是必要的,用来指向Fragment的定义,其他的属性和一般的一样设置就可以了。
现在可以写轮播的Fragment的代码了(很简单的逻辑,我就不解释了,重要的地方有注释):
获取新闻数据接口是来自聚合网,
下面贴出轮播Viewpager中的内容Fragment:
图片加载我使用的是Glide库,详细的使用方法(点击开启传送门)。
下面说一下我遇到的bug,在包含tablayout的布局中,没有设置tab的最大宽度值,导致数量多了之后看不到背景图片(这么简单的问题,蜗居然改本来就是能用的代码改了大半天!!后来突然想到改少tab数量会不会有效才发现问题所在,在这里做个记录,以防再次入坑。)
下面是截图(可以看到效果已经实现了,但是tab间距太远):
于是我们调整一下tablayout的padding值以及tabMaxWidth的值:
改变之后的tablayout如下:
注意必须三个padding和MaxWidth同时设置才能有如下效果,缺一不可!!
注意必须三个padding和MaxWidth同时设置才能有如下效果,缺一不可!!
注意必须三个padding和MaxWidth同时设置才能有如下效果,缺一不可!!
最后截图,原谅我没有截成gif。实在不会用咔咔截屏。。。。
如有问题,欢迎指正。
现在来看看效果:
源码传送门
最近在做一个新闻APP,看到现在的新闻客户端顶端都有个热点新闻轮播。
思路:viewpager可以用来显示图片,并且可以提供滑动,15年(不知记错没)新出的TabLayout可以绑定ViewPager的Adapter来实现ViewPager与Tablayout的联动效果,比如qq的下面菜单栏,微信的菜单栏,都可以这样实现。而且我们可以通过两种方式来实现TabLayout的图片标题:
1.SpannableString 来实现图文混排,混排方法(传送门)。
2.使用自定义布局,布局中添加你想要显示的内容,然后调用tablayout中tab的setCustomView(View view)或者setCustomView(int R_id)方法来设置显示。
下面正题:
这里我使用第二种方法来实现,至于为什么用第二种(好吧其实是我使用第一种的时候遇到了一个不显示的bug,当然第二种也遇到了,后面会提及,后来就没改回第一种了,原理一样)源码在最后面有下载。
一。首先我们来准备图片:
没有选中的位置的提示图片:
选中了之后的位置的提示图片:
图片都可以使用ps制作,很简单。
二。然后我们来写轮播界面的布局(老规矩,先代码后解释):
<?xml version="1.0" encoding="utf-8"?> <!--轮播viewpager布局--> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="200dp"> <android.support.design.widget.TabLayout app:tabIndicatorColor="@color/colorTransparent" android:id="@+id/luobo_tablayout" android:layout_width="100dp" android:layout_height="10dp" app:tabMinWidth="10dp" app:tabMaxWidth="30dp" app:tabGravity="center" app:tabMode="fixed" android:layout_alignParentEnd="true" android:layout_alignParentBottom="true" android:translationZ="2dp" android:layout_marginBottom="5dp"/> <android.support.v4.view.ViewPager android:id="@+id/luobo_viewpager" android:layout_width="match_parent" android:layout_height="match_parent" android:translationZ="0dp" > </android.support.v4.view.ViewPager> </RelativeLayout>这里解释几个点:
(1)translationZ属性:为了让Tablayout显示在Viewpager的上方,不设置z值大于ViewPager的话,就显示不出来了。
(2)tabMode属性:为了不让tablayout滑动(在内容超出控件宽度的时候里面内容滑动从而造成显示上的逻辑错误)。
(3)tabMinWidth属性:
tabMaxWidth属性:设置tab的最小值和最大值,来控制每个tab的宽度(先立个Flag)。
三。现在我们来为ViewPager的内容写布局文件,这里我们的内容有新闻图片(覆盖全页面),新闻标题(位于左下角),
布局文件如下:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="200dp"> <ImageView android:id="@+id/imageLayout_Image" android:layout_width="match_parent" android:layout_height="200dp" android:background="@mipmap/winter_news_place_hloder_pic" android:src="@color/colorTransparent"/> <TextView android:id="@+id/imageLayout_Title" android:textColor="@color/colorWrite" android:layout_width="200dp" android:marqueeRepeatLimit="marquee_forever" android:maxLines="1" android:layout_height="20dp" android:layout_alignParentBottom="true" android:textAlignment="viewStart" android:layout_marginLeft="15dp"/> </RelativeLayout>这里设置了图片为默认的占位图片。可根据喜好设置。
四。既然我们要自定义tablayout的布局,那么我们现在就来写这个布局文件
布局很简单,就一个ImageView,为了拉伸图片到全部页面,我们这里设置他的background属性而不是src属性:
<?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="match_parent"> <ImageView android:id="@+id/Imageview" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@mipmap/luobo_unseleted"/> </LinearLayout>
五。布局我们已经弄好了,接下来就是逻辑代码了,我这里使用继承自Fragment是为了方便插入任何其他布局里,我这里插入的是首页。
这里插播一下布局中插入碎片(Fragment)的方法,老规矩:
<fragment android:layout_width="match_parent" android:layout_height="200dp" android:id="@+id/luoboViewPaget" android:name="lunbo.viewPagerLuobo"/>
注意上面的name属性是必要的,用来指向Fragment的定义,其他的属性和一般的一样设置就可以了。
现在可以写轮播的Fragment的代码了(很简单的逻辑,我就不解释了,重要的地方有注释):
package lunbo; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.icu.text.LocaleDisplayNames; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.support.annotation.Nullable; import android.support.design.widget.TabLayout; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentPagerAdapter; import android.support.v4.content.ContextCompat; import android.support.v4.view.ViewPager; import android.support.v7.app.WindowDecorActionBar; import android.text.Spannable; import android.text.SpannableString; import android.text.style.ImageSpan; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import com.android.volley.RequestQueue; import com.android.volley.Response; import com.android.volley.VolleyError; import com.android.volley.toolbox.StringRequest; import java.util.ArrayList; import NewsInfo.JUHE_NewsInfo; import Static.StaticValue; import Util.FileOP.FileStore; import Util.NetWork; import winter.zxb.smilesb101.winternews.R; /** * 项目名称:WinterNews * 类描述:图片轮播类 * 创建人:SmileSB101 * 创建时间:2016/11/9 0009 07:36 * 修改人:Administrator * 修改时间:2016/11/9 0009 07:36 * 修改备注: */ public class viewPagerLuobo extends Fragment{ private TabLayout mTablayout; private ViewPager mViewPager; private int selectNum; private int pageNum; private View view; private ArrayList<JUHE_NewsInfo> juhe_newsInfos = new ArrayList<>(); private viewPagerAdapter mViewPageAdapter; private static final int GetNewsDown = 0; private static final int GetNewsError = -1; private Handler handler = new Handler(){ @Override public void handleMessage(Message msg){ super.handleMessage(msg); switch(msg.what) { case GetNewsDown: Log.i("设置轮播图片显示","handleMessage: "); showTopNews(); break; case GetNewsError: break; } } }; @Nullable @Override public View onCreateView(LayoutInflater inflater,@Nullable ViewGroup container,@Nullable Bundle savedInstanceState){ view = inflater.inflate(R.layout.lunbo_viewpager,container,false); selectNum = 0; pageNum = 3; getTopNews(); return view; } private void getTopNews() { RequestQueue mrequeue = NetWork.getmRequestqueue(StaticValue.MainActivity); String utl = "http://v.juhe.cn/toutiao/index?top&key=2d89bbcc668f4ef02cade2b00d7d9265"; StringRequest stringRequest = new StringRequest(utl,new Response.Listener<String>(){ @Override public void onResponse(String s){ Log.i("获取到头条","onResponse: "); juhe_newsInfos = FileStore.getJUHENews_List(s); handler.sendEmptyMessage(GetNewsDown); } },new Response.ErrorListener(){ @Override public void onErrorResponse(VolleyError volleyError){ handler.sendEmptyMessage(GetNewsError); } }); mrequeue.add(stringRequest); } private void showTopNews() { mViewPager = (ViewPager)view.findViewById(R.id.luobo_viewpager); mViewPageAdapter = new viewPagerAdapter(getFragmentManager()); mViewPager.setAdapter(mViewPageAdapter); setmTablayout(); } private void setmTablayout() { mTablayout = (TabLayout)view.findViewById(R.id.luobo_tablayout); mTablayout.setupWithViewPager(mViewPager); //添加tab,这里添加一开始显示的图片,重要代码 for(int i = 0;i<mViewPageAdapter.getCount();i++) { TabLayout.Tab tab = mTablayout.getTabAt(i); Log.i("添加图片","setmTablayout: 1"); View v = LayoutInflater.from(StaticValue.MainActivity).inflate(R.layout.luobo_tablayout,null); ImageView tabImage = (ImageView)v.findViewById(R.id.Imageview); tabImage.setBackgroundResource(R.mipmap.luobo_unseleted); tab.setCustomView(v); } //添加图片变换,在这里进行选项变化时图片的设置,重要代码 mTablayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener(){ @Override public void onTabSelected(TabLayout.Tab tab){ Log.i("图片添加","onTabSelected: "); View v = tab.getCustomView(); ImageView tabImage = (ImageView)v.findViewById(R.id.Imageview); tabImage.setBackgroundResource(R.mipmap.luobo_seleted); //tab.setCustomView(v); } @Override public void onTabUnselected(TabLayout.Tab tab){ View v = tab.getCustomView(); ImageView tabImage = (ImageView)v.findViewById(R.id.Imageview); tabImage.setBackgroundResource(R.mipmap.luobo_unseleted); //tab.setCustomView(v); } @Override public void onTabReselected(TabLayout.Tab tab){ } }); //后台开启计时器线程,每3秒设置一次选项变化,实现轮播的逻辑,重要代码。 handler.postDelayed(new Runnable(){ @Override public void run(){ selectNum = selectNum%pageNum; Log.i("选项卡数量","run: "+selectNum); mViewPager.setCurrentItem(selectNum); selectNum++; handler.postDelayed(this,3000); } },0); } class viewPagerAdapter extends FragmentPagerAdapter{ public viewPagerAdapter(FragmentManager fm){ super(fm); } @Override public int getCount(){ return pageNum; } @Override public Fragment getItem(int position){ return ImageFragment.newInstence(juhe_newsInfos.get(position)); } @Override public CharSequence getPageTitle(int position){ return ""; } } }
获取新闻数据接口是来自聚合网,
下面贴出轮播Viewpager中的内容Fragment:
package lunbo; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; import com.bumptech.glide.Glide; import com.bumptech.glide.load.resource.drawable.GlideDrawable; import com.bumptech.glide.request.animation.GlideAnimation; import com.bumptech.glide.request.target.SimpleTarget; import NewsInfo.JUHE_NewsInfo; import winter.zxb.smilesb101.winternews.R; /** * 项目名称:WinterNews * 类描述:轮播ViewPager中显示的内容的Fragment * 创建人:SmileSB101 * 创建时间:2016/11/9 0009 13:24 * 修改人:Administrator * 修改时间:2016/11/9 0009 13:24 * 修改备注: */ public class ImageFragment extends Fragment{ private ImageView mImageView; private JUHE_NewsInfo juhe_newsInfo; private TextView title; Fragment context; public void setJuhe_newsInfo(JUHE_NewsInfo juhe_newsInfo) { this.juhe_newsInfo = juhe_newsInfo; } public ImageFragment(){ } public static ImageFragment newInstence(JUHE_NewsInfo juhe_newsInfo) { ImageFragment imageFragment = new ImageFragment(); imageFragment.setJuhe_newsInfo(juhe_newsInfo); return imageFragment; } @Nullable @Override public View onCreateView(LayoutInflater inflater,@Nullable ViewGroup container,@Nullable Bundle savedInstanceState){ View rootView = null; context = this; rootView = inflater.inflate(R.layout.image_layout,container,false); title = (TextView)rootView.findViewById(R.id.imageLayout_Title); mImageView = (ImageView)rootView.findViewById(R.id.imageLayout_Image); if(juhe_newsInfo!=null) { Glide.with(context) .load(juhe_newsInfo.getThumbnail_pic_s()) .placeholder(R.mipmap.winter_news_place_hloder_pic) .error(R.mipmap.winter_news_error_pic) .into(new SimpleTarget<GlideDrawable>(){ @Override public void onResourceReady(GlideDrawable resource,GlideAnimation<? super GlideDrawable> glideAnimation){ //在这里设置图片背景(当GLide获取完成图片之后执行) mImageView.setBackground(resource); } }); title.setText(juhe_newsInfo.getTitle()); } else { Glide.with(context) .load(R.mipmap.winter_news_place_hloder_pic) .error(R.mipmap.winter_news_error_pic) .into(new SimpleTarget<GlideDrawable>(){ @Override public void onResourceReady(GlideDrawable resource,GlideAnimation<? super GlideDrawable> glideAnimation){ //在这里设置图片背景(当GLide获取完成图片之后执行) mImageView.setBackground(resource); } }); } return rootView; } }
图片加载我使用的是Glide库,详细的使用方法(点击开启传送门)。
下面说一下我遇到的bug,在包含tablayout的布局中,没有设置tab的最大宽度值,导致数量多了之后看不到背景图片(这么简单的问题,蜗居然改本来就是能用的代码改了大半天!!后来突然想到改少tab数量会不会有效才发现问题所在,在这里做个记录,以防再次入坑。)
下面是截图(可以看到效果已经实现了,但是tab间距太远):
于是我们调整一下tablayout的padding值以及tabMaxWidth的值:
改变之后的tablayout如下:
<android.support.design.widget.TabLayout app:tabIndicatorColor="@color/colorTransparent" android:id="@+id/luobo_tablayout" android:layout_width="100dp" android:layout_height="10dp" app:tabMinWidth="10dp" app:tabMaxWidth="10dp" app:tabPadding="0dp" app:tabPaddingStart="0dp" app:tabPaddingEnd="0dp" app:tabGravity="center" app:tabMode="fixed" android:layout_alignParentEnd="true" android:layout_alignParentBottom="true" android:translationZ="2dp" android:layout_marginBottom="5dp"/>这里控件的宽度可以自己根据实际需求更改
注意必须三个padding和MaxWidth同时设置才能有如下效果,缺一不可!!
注意必须三个padding和MaxWidth同时设置才能有如下效果,缺一不可!!
注意必须三个padding和MaxWidth同时设置才能有如下效果,缺一不可!!
最后截图,原谅我没有截成gif。实在不会用咔咔截屏。。。。
如有问题,欢迎指正。
现在来看看效果:
源码传送门
相关文章推荐
- Android进阶之利用Tablayout+ViewPager+Fragment实现神奇的滑动效果
- Android中TabLayout结合ViewPager实现页面切换效果
- RollViewPager简单实现android图片轮播效果
- Android 中基于TabLayout+ViewPager实现标签卡效果
- Android之利用Viewpager实现图片的轮播效果
- Android 导航条效果实现(六) TabLayout+ViewPager+Fragment
- Android中ViewPager实现图片的定时轮播效果(设置Integer.MAX_VALUE)
- Android Viewpager实现图片轮播(仿优酷效果)
- Android中ViewPager的使用(二):实现图片轮播效果
- 安卓 TabLayout+ViewPager实现滑动Tab效果
- Android Viewpager实现图片轮播(仿优酷效果)
- Android Viewpager实现图片轮播(仿优酷效果)
- Android中TabLayout+ViewPager实现tab和页面联动效果
- android之TabLayout实现PagerSlidingTabStrip,ViewpagerIndicator之类的效果滑动页面导航效果(类似网易新闻)
- RollViewPager实现android图片轮播效果
- Android开发之CoordinatorLayoutAppBarLayoutViewPagerTabLayout实现顶部伸缩效果
- Android ViewPager实现图片轮播效果
- android,侧滑栏SlidingLayout、ViewPager实现画廊、简单用viewpager实现画廊、圆形图片、简单的跑马灯动画效果、可拖拽的弹簧式水泡动画集合
- Android开发之CoordinatorLayoutAppBarLayoutViewPagerTabLayout实现顶部伸缩效果
- android viewPager实现轮播效果一(本地图片篇)