ViewPager无限循环实现画廊式banner
16lz
2021-01-23
先看一下效果
两边显示上一个和下一个item部分布局,可以自动滚动
实现:
布局
主要属性:android:clipChildren="false" //允许子布局超出父布局显示
xml代码:
<?xml version="1.0" encoding="utf-8"?>
Adapter
没什么特别的只要 getCount()返回一个很大的值如:return Integer.MAX_VALUE;
适配器代码:
package com.guzhc.module_demo;import android.content.Context;import android.view.View;import android.view.ViewGroup;import android.view.ViewParent;import android.widget.ImageView;import android.widget.TextView;import androidx.annotation.NonNull;import androidx.viewpager.widget.PagerAdapter;import com.bumptech.glide.Glide;import java.util.ArrayList;import java.util.List;/** * @author : GuZhC * @date : 2019/6/1 9:46 * @description : 顶部banner viewPager 适配器 */public class ShortViewoViewPagerAdapter extends PagerAdapter { private final Context context; private final List mData; private PagerClick pagerClick; public ShortViewoViewPagerAdapter(List mData, Context context) { this.mData = mData; this.context = context; } @Override public int getCount() { return Integer.MAX_VALUE; } @Override public void destroyItem(ViewGroup container, int position, Object object) { //Warning:不要在这里调用removeView } @Override public boolean isViewFromObject(@NonNull View view, @NonNull Object object) { return view == object; } @Override public Object instantiateItem(ViewGroup container, int position) { position %= mData.size(); final String data = mData.get(position); View view = View.inflate(container.getContext(),R.layout.demo_item_short_video_viewpager, null); ImageView img = view.findViewById(R.id.demo_img_short_video_item); TextView tvContent = view.findViewById(R.id.demo_tv_short_video_item); tvContent.setText(data); Glide.with(context) .load("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1559367407524&di=2a7d6a1a12707287e908d61922a637c2&imgtype=0&src=http%3A%2F%2Fpic72.nipic.com%2Ffile%2F20150715%2F9448607_192612583000_2.jpg") .into(img); //对ViewPager页号求模取出View列表中要显示的项 if (position < 0) { position = mData.size() + position; } //如果View已经在之前添加到了一个父组件,则必须先remove,否则会抛出IllegalStateException。 ViewParent vp = view.getParent(); if (vp != null) { ViewGroup parent = (ViewGroup) vp; parent.removeView(view); } container.addView(view); return view; } }
调用
注意:两边的item滑动没有效果吗,需要将容器的触摸事件反馈给ViewPager
//设置banner shortViewoViewPagerAdapter = new ShortViewoViewPagerAdapter(mData, getContext()); View bannerView = LayoutInflater.from(getContext()).inflate(R.layout.demo_layout_short_video_banner, null); viewPagerBanner = bannerView.findViewById(R.id.demo_vp_short_video_top); LinearLayout mViewPagerContainer = bannerView.findViewById(R.id.demo_ll_short_video_vp_root); viewPagerBanner.setAdapter(shortViewoViewPagerAdapter); viewPagerBanner.addOnPageChangeListener(this); //将容器的触摸事件反馈给ViewPager mViewPagerContainer.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { return viewPagerBanner.dispatchTouchEvent(event); } });
无限循环:方式很多,这里用的Handler实现
设置viewPager.addOnPageChangeListener(this)实现接口重写方法:实现滑动时候暂停自动滑动,停止的时候开启
重写方法代码:
@Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { handler.sendMessage(Message.obtain(handler, ImageHandler.MSG_PAGE_CHANGED, position, 0)); } @Override public void onPageSelected(int position) { } @Override public void onPageScrollStateChanged(int state) { switch (state) { //滑动中 case ViewPager.SCROLL_STATE_DRAGGING: handler.sendEmptyMessage(ImageHandler.MSG_KEEP_SILENT); break; //未滑动 case ViewPager.SCROLL_STATE_IDLE: handler.sendEmptyMessageDelayed(ImageHandler.MSG_UPDATE_IMAGE, ImageHandler.MSG_DELAY); break; default: break; } }
Handler代码:
public class ImageHandler extends Handler { /** * 请求更新显示的View。 */ protected static final int MSG_UPDATE_IMAGE = 1; /** * 请求暂停轮播。 */ protected static final int MSG_KEEP_SILENT = 2; /** * 请求恢复轮播。 */ protected static final int MSG_BREAK_SILENT = 3; /** * 记录最新的页号,当用户手动滑动时需要记录新页号,否则会使轮播的页面出错。 * 例如当前如果在第一页,本来准备播放的是第二页,而这时候用户滑动到了末页, * 则应该播放的是第一页,如果继续按照原来的第二页播放,则逻辑上有问题。 */ protected static final int MSG_PAGE_CHANGED = 4; //轮播间隔时间 protected static final long MSG_DELAY = 5000; //使用弱引用避免Handler泄露. private WeakReference weakReference; private int currentItem = 0; protected ImageHandler(WeakReference wk){ weakReference = wk; } @Override public void handleMessage(Message msg) { super.handleMessage(msg); ShortVedioFragmet shortVedioFragmet = weakReference.get(); if (shortVedioFragmet==null){ //Activity已经回收,无需再处理UI了 return ; } //检查消息队列并移除未发送的消息,这主要是避免在复杂环境下消息出现重复等问题。 if (shortVedioFragmet.handler.hasMessages(MSG_UPDATE_IMAGE)){ shortVedioFragmet.handler.removeMessages(MSG_UPDATE_IMAGE); } switch (msg.what) { case MSG_UPDATE_IMAGE: currentItem++; shortVedioFragmet.viewPagerBanner.setCurrentItem(currentItem); //准备下次播放 shortVedioFragmet.handler.sendEmptyMessageDelayed(MSG_UPDATE_IMAGE, MSG_DELAY); break; case MSG_KEEP_SILENT: //只要不发送消息就暂停了 break; case MSG_BREAK_SILENT: shortVedioFragmet.handler.sendEmptyMessageDelayed(MSG_UPDATE_IMAGE, MSG_DELAY); break; case MSG_PAGE_CHANGED: //记录当前的页号,避免播放的时候页面显示不正确。 currentItem = msg.arg1; break; default: break; } }}
如果是viewpager嵌套Fragment的界面中使用可以通过setUserVisibleHint(boolean isVisibleToUser)方法这样开启和暂停:
setUserVisibleHint()方法会在fragment显示和隐藏的时候被调用
@Override public void setUserVisibleHint(boolean isVisibleToUser) { super.setUserVisibleHint(isVisibleToUser); if(isVisibleToUser) { //相当于OnResume(),可以做相关逻辑 //开始轮播效果 handler.sendEmptyMessageDelayed(ImageHandler.MSG_UPDATE_IMAGE, ImageHandler.MSG_DELAY); }else { //相当于OnPause() //暂停轮播效果 handler.sendEmptyMessage(ImageHandler.MSG_KEEP_SILENT); } }
在Activity使用 可以在onResum() 和onPause()开启可暂停。
至此完成。
更多相关文章
- 安卓霓虹灯效果
- 后台动态添加布局文件、控件与动态设置属性2
- Android TextView 中文本横向滚动效果实现
- androidUI布局仿猫扑界面
- Android UI开发第八篇――ViewFlipper 左右滑动效果
- [Tools]Android Studio代码提示功能--Ctrl+Alt+Space(空格键)
- Android Layout 布局 && Android自带样式(theme)&& CheckBox样例 &
- 使用Android常用控件与布局实现美观的登录页面