使用ViewPager实现广告轮播图
使用的是DialogFragment, 布局文件:fragment_ads_dialog
<?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">
<android.support.v4.view.ViewPager
android:id="@+id/ads_view_pager"
android:layout_width="match_parent"
android:layout_height="200dp"
android:layout_centerInParent="true"
/>
<ImageView
android:id="@+id/dismiss"
android:layout_below="@id/ads_view_pager"
android:src="@mipmap/ic_launcher"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
继承 DialogFragment
public class AdFragment extends DialogFragment {
@BindView(R.id.ads_view_pager)
ViewPager viewPager;
@BindView(R.id.dismiss)
ImageView dismiss;
Unbinder unbinder;
private int[] drawableIds = new int[]{R.drawable.a, R.drawable.b, R.drawable.c, R.drawable.d};
private List<View> views = new ArrayList<>();
private List<Integer> drawableList;
private Handler handler = new Handler();
private boolean stopAutoScroll = false;
private Runnable autoScrollRunnable = new Runnable() {
@Override
public void run() {
if (!stopAutoScroll) {
int currentItem = viewPager.getCurrentItem();
viewPager.setCurrentItem(currentItem + 1, true);
handler.postDelayed(autoScrollRunnable, 3000);
}
}
};
@Nullable
@Override
public View onCreateView(LayoutInflater inflater,
@Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_ads_dialog, container, false);
unbinder = ButterKnife.bind(this, view);
WindowManager.LayoutParams params = getDialog().getWindow().getAttributes();
params.windowAnimations = R.style.main_menu_animstyle;
getDialog().getWindow().setAttributes(params);
getDialog().requestWindowFeature(Window.FEATURE_NO_TITLE);
getDialog().getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
getDialog().setCanceledOnTouchOutside(false);
initView();
return view;
}
private void initView() {
initData();
createPageItems();
ViewPagerScroller pagerScroller = new ViewPagerScroller(getActivity());
pagerScroller.setScrollDuration(1500);//设置时间,时间越长,速度越慢
pagerScroller.initViewPagerScroll(viewPager);
viewPager.setAdapter(new MyPagerAdapter());
viewPager.addOnPageChangeListener(new CycleScrollOnPageChangeListener());
// 当滑到第0页时,position 会设置到 views.size() - 2
// 先对其初始化,防止 setCurrentItem 因为时间延迟而出现闪动
viewPager.setCurrentItem(1, false);
viewPager.setPageTransformer(false, new CubeOutTransformer());
}
private void createPageItems() {
for (int i = 0; i < drawableList.size(); i++) {
ImageView imageView = new ImageView(getContext());
imageView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams
.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
imageView.setScaleType(ImageView.ScaleType.FIT_XY);
imageView.setImageResource(drawableList.get(i));
views.add(imageView);
}
}
private void initData() {
drawableList = new ArrayList<Integer>();
drawableList.add(drawableIds[drawableIds.length - 1]);
for (int id : drawableIds) {
drawableList.add(id);
}
drawableList.add(drawableIds[0]);
}
@Override
public void onStart() {
super.onStart();
Dialog dialog = getDialog();
if (dialog != null) {
DisplayMetrics dm = new DisplayMetrics();
getActivity().getWindowManager().getDefaultDisplay().getMetrics(dm);
dialog.getWindow()
.setLayout((int) (dm.widthPixels * 0.8), ViewGroup.LayoutParams.WRAP_CONTENT);
}
}
@Override
public void onResume() {
super.onResume();
handler.postDelayed(autoScrollRunnable, 3000);
}
@Override
public void onPause() {
super.onPause();
handler.removeCallbacksAndMessages(null);
}
@Override
public void onDestroyView() {
super.onDestroyView();
unbinder.unbind();
}
@OnClick(R.id.dismiss)
public void onViewClicked() {
dismiss();
}
class CycleScrollOnPageChangeListener implements ViewPager.OnPageChangeListener {
@Override
public void onPageSelected(int arg0) {
}
@Override
public void onPageScrolled(int position, float offset, int offsetPixels) {
if (offset == 0) {
if (position == 0) {
viewPager.setCurrentItem(views.size() - 2, false);
} else if (position == (views.size() - 1)) {
viewPager.setCurrentItem(1, false);
}
}
}
@Override
public void onPageScrollStateChanged(int arg0) {
}
}
class MyPagerAdapter extends PagerAdapter {
@Override
public int getCount() {
return views.size();
}
@Override
public boolean isViewFromObject(View arg0, Object arg1) {
return arg0 == arg1;
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
View view = views.get(position);
container.addView(view);
return view;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView(views.get(position));
}
}
@OnTouch(R.id.ads_view_pager)
public boolean onViewTouch(View view, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
stopAutoScroll = true;
handler.removeCallbacks(autoScrollRunnable);
handler.removeCallbacksAndMessages(null);
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
stopAutoScroll = false;
handler.postDelayed(autoScrollRunnable, 3000);
break;
}
return false;
}
}
过程解析
WindowManager.LayoutParams params = getDialog().getWindow().getAttributes();
params.windowAnimations = R.style.main_menu_animstyle;
getDialog().getWindow().setAttributes(params);
getDialog().requestWindowFeature(Window.FEATURE_NO_TITLE);
getDialog().getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
getDialog().setCanceledOnTouchOutside(false);
该段代码主要用来设置dialog的样式,透明及无标题
ViewPagerScroller pagerScroller = new ViewPagerScroller(getActivity());
pagerScroller.setScrollDuration(1500);//设置时间,时间越长,速度越慢
pagerScroller.initViewPagerScroll(viewPager);
用于设置ViewPager每一页的切换速度,其中ViewPagerScroller类如下
public class ViewPagerScroller extends Scroller {
private int mScrollDuration = 2000; // 滑动速度
/**
* 设置速度速度
*
* @param duration
*/
public void setScrollDuration(int duration) {
this.mScrollDuration = duration;
}
public ViewPagerScroller(Context context) {
super(context);
}
public ViewPagerScroller(Context context, Interpolator interpolator) {
super(context, interpolator);
}
public ViewPagerScroller(Context context, Interpolator interpolator,
boolean flywheel) {
super(context, interpolator, flywheel);
}
@Override
public void startScroll(int startX, int startY, int dx, int dy, int duration) {
super.startScroll(startX, startY, dx, dy, mScrollDuration);
}
@Override
public void startScroll(int startX, int startY, int dx, int dy) {
super.startScroll(startX, startY, dx, dy, mScrollDuration);
}
public void initViewPagerScroll(ViewPager viewPager) {
try {
Field mScroller = ViewPager.class.getDeclaredField("mScroller");
mScroller.setAccessible(true);
mScroller.set(viewPager, this);
} catch (Exception e) {
e.printStackTrace();
}
}
}
在onStart 生命周期中,设置dialog的宽高
@Override
public void onStart() {
super.onStart();
Dialog dialog = getDialog();
if (dialog != null) {
DisplayMetrics dm = new DisplayMetrics();
getActivity().getWindowManager().getDefaultDisplay().getMetrics(dm);
dialog.getWindow()
.setLayout((int) (dm.widthPixels * 0.8), ViewGroup.LayoutParams.WRAP_CONTENT);
}
}
重点部分是实现Viewpager的无限制滑动,默认在数据源列表的收尾,再添加两个item,如下;
private void initData() {
drawableList = new ArrayList<Integer>();
drawableList.add(drawableIds[drawableIds.length - 1]);
for (int id : drawableIds) {
drawableList.add(id);
}
drawableList.add(drawableIds[0]);
}
然后在滑动的时候,作如下处理
@Override
public void onPageScrolled(int position, float offset, int offsetPixels) {
if (offset == 0) {
if (position == 0) {
viewPager.setCurrentItem(views.size() - 2, false);
} else if (position == (views.size() - 1)) {
viewPager.setCurrentItem(1, false);
}
}
}
具体可以参看循环 ViewPager 的两种实现方法
至于,自动轮播则是使用了Handler消息机制
private Runnable autoScrollRunnable = new Runnable() {
@Override
public void run() {
if (!stopAutoScroll) {
int currentItem = viewPager.getCurrentItem();
viewPager.setCurrentItem(currentItem + 1, true);
handler.postDelayed(autoScrollRunnable, 3000);
}
}
};
另外附上ViewPager相关转场动画
基类
public abstract class ABaseTransformer implements PageTransformer {
/**
* Called each {@link #transformPage(View, float)}.
*
* @param view
* @param position
*/
protected abstract void onTransform(View view, float position);
@Override
public void transformPage(View view, float position) {
onPreTransform(view, position);
onTransform(view, position);
onPostTransform(view, position);
}
/**
* If the position offset of a fragment is less than negative one or greater than one, returning true will set the
* visibility of the fragment to {@link View#GONE}. Returning false will force the fragment to {@link View#VISIBLE}.
*
* @return
*/
protected boolean hideOffscreenPages() {
return true;
}
/**
* Indicates if the default animations of the view pager should be used.
*
* @return
*/
protected boolean isPagingEnabled() {
return false;
}
/**
* Called each {@link #transformPage(View, float)} before {{@link #onTransform(View, float)} is called.
*
* @param view
* @param position
*/
protected void onPreTransform(View view, float position) {
final float width = view.getWidth();
view.setRotationX(0);
view.setRotationY(0);
view.setRotation(0);
view.setScaleX(1);
view.setScaleY(1);
view.setPivotX(0);
view.setPivotY(0);
view.setTranslationY(0);
view.setTranslationX(isPagingEnabled() ? 0f : -width * position);
if (hideOffscreenPages()) {
view.setAlpha(position <= -1f || position >= 1f ? 0f : 1f);
} else {
view.setAlpha(1f);
}
}
/**
* Called each {@link #transformPage(View, float)} call after {@link #onTransform(View, float)} is finished.
*
* @param view
* @param position
*/
protected void onPostTransform(View view, float position) {
}
}
public class AccordionTransformer extends ABaseTransformer {
@Override
protected void onTransform(View view, float position) {
view.setPivotX(position < 0 ? 0 : view.getWidth());
view.setScaleX(position < 0 ? 1f + position : 1f - position);
}
}
public class BackgroundToForegroundTransformer extends ABaseTransformer {
@Override
protected void onTransform(View view, float position) {
final float height = view.getHeight();
final float width = view.getWidth();
final float scale = min(position < 0 ? 1f : Math.abs(1f - position), 0.5f);
view.setScaleX(scale);
view.setScaleY(scale);
view.setPivotX(width * 0.5f);
view.setPivotY(height * 0.5f);
view.setTranslationX(position < 0 ? width * position : -width * position * 0.25f);
}
private static final float min(float val, float min) {
return val < min ? min : val;
}
}
public class CubeInTransformer extends ABaseTransformer {
@Override
protected void onTransform(View view, float position) {
// Rotate the fragment on the left or right edge
view.setPivotX(position > 0 ? 0 : view.getWidth());
view.setPivotY(0);
view.setRotationY(-90f * position);
}
@Override
public boolean isPagingEnabled() {
return true;
}
}
public class CubeOutTransformer extends ABaseTransformer {
@Override
protected void onTransform(View view, float position) {
view.setPivotX(position < 0f ? view.getWidth() : 0f);
view.setPivotY(view.getHeight() * 0.5f);
view.setRotationY(90f * position);
}
@Override
public boolean isPagingEnabled() {
return true;
}
}
public class DepthPageTransformer extends ABaseTransformer {
private static final float MIN_SCALE = 0.75f;
@Override
protected void onTransform(View view, float position) {
if (position <= 0f) {
view.setTranslationX(0f);
view.setScaleX(1f);
view.setScaleY(1f);
} else if (position <= 1f) {
final float scaleFactor = MIN_SCALE + (1 - MIN_SCALE) * (1 - Math.abs(position));
view.setAlpha(1 - position);
view.setPivotY(0.5f * view.getHeight());
view.setTranslationX(view.getWidth() * -position);
view.setScaleX(scaleFactor);
view.setScaleY(scaleFactor);
}
}
@Override
protected boolean isPagingEnabled() {
return true;
}
}
public class FlipHorizontalTransformer extends ABaseTransformer {
@Override
protected void onTransform(View view, float position) {
final float rotation = 180f * position;
view.setAlpha(rotation > 90f || rotation < -90f ? 0 : 1);
view.setPivotX(view.getWidth() * 0.5f);
view.setPivotY(view.getHeight() * 0.5f);
view.setRotationY(rotation);
}
}
public class FlipVerticalTransformer extends ABaseTransformer {
@Override
protected void onTransform(View view, float position) {
final float rotation = -180f * position;
view.setAlpha(rotation > 90f || rotation < -90f ? 0f : 1f);
view.setPivotX(view.getWidth() * 0.5f);
view.setPivotY(view.getHeight() * 0.5f);
view.setRotationX(rotation);
}
}
public class ForegroundToBackgroundTransformer extends ABaseTransformer {
@Override
protected void onTransform(View view, float position) {
final float height = view.getHeight();
final float width = view.getWidth();
final float scale = min(position > 0 ? 1f : Math.abs(1f + position), 0.5f);
view.setScaleX(scale);
view.setScaleY(scale);
view.setPivotX(width * 0.5f);
view.setPivotY(height * 0.5f);
view.setTranslationX(position > 0 ? width * position : -width * position * 0.25f);
}
private static final float min(float val, float min) {
return val < min ? min : val;
}
}
public class RotateDownTransformer extends ABaseTransformer {
private static final float ROT_MOD = -15f;
@Override
protected void onTransform(View view, float position) {
final float width = view.getWidth();
final float height = view.getHeight();
final float rotation = ROT_MOD * position * -1.25f;
view.setPivotX(width * 0.5f);
view.setPivotY(height);
view.setRotation(rotation);
}
@Override
protected boolean isPagingEnabled() {
return true;
}
}
public class RotatePageTransformer implements ViewPager.PageTransformer {
private float maxRotate = 90f; // 最大旋转角度
@Override
public void transformPage(View page, float position) {
if (position < -1){
page.setPivotX(page.getWidth());
page.setPivotY(page.getHeight()/2 );
page.setRotationY(-maxRotate);
}else if(position < 0){
page.setPivotX(page.getWidth() * (0.5f + 0.5f * (- position))); // X轴支点坐标变化范围[page
// .getWidth()/2, page.getWidth()]
page.setPivotY(page.getHeight()/2 );
page.setRotationY(maxRotate * position);
}else if(position <= 1){
page.setPivotX(page.getWidth() * 0.5f * (1 - position)); // // X轴支点坐标变化范围[0, page
// .getWidth()/2]
page.setPivotY(page.getHeight()/2 );
page.setRotationY(maxRotate * position);
}else{
page.setPivotX(0);
page.setPivotY(page.getHeight()/2 );
page.setRotationY(maxRotate);
}
}
}
public class RotateUpTransformer extends ABaseTransformer {
private static final float ROT_MOD = -15f;
@Override
protected void onTransform(View view, float position) {
final float width = view.getWidth();
final float rotation = ROT_MOD * position;
view.setPivotX(width * 0.5f);
view.setPivotY(0f);
view.setTranslationX(0f);
view.setRotation(rotation);
}
@Override
protected boolean isPagingEnabled() {
return true;
}
}
public class StackTransformer extends ABaseTransformer {
@Override
protected void onTransform(View view, float position) {
view.setTranslationX(position < 0 ? 0f : -view.getWidth() * position);
}
}
public class TabletTransformer extends ABaseTransformer {
private static final Matrix OFFSET_MATRIX = new Matrix();
private static final Camera OFFSET_CAMERA = new Camera();
private static final float[] OFFSET_TEMP_FLOAT = new float[2];
@Override
protected void onTransform(View view, float position) {
final float rotation = (position < 0 ? 30f : -30f) * Math.abs(position);
view.setTranslationX(getOffsetXForRotation(rotation, view.getWidth(), view.getHeight()));
view.setPivotX(view.getWidth() * 0.5f);
view.setPivotY(0);
view.setRotationY(rotation);
}
protected static final float getOffsetXForRotation(float degrees, int width, int height) {
OFFSET_MATRIX.reset();
OFFSET_CAMERA.save();
OFFSET_CAMERA.rotateY(Math.abs(degrees));
OFFSET_CAMERA.getMatrix(OFFSET_MATRIX);
OFFSET_CAMERA.restore();
OFFSET_MATRIX.preTranslate(-width * 0.5f, -height * 0.5f);
OFFSET_MATRIX.postTranslate(width * 0.5f, height * 0.5f);
OFFSET_TEMP_FLOAT[0] = width;
OFFSET_TEMP_FLOAT[1] = height;
OFFSET_MATRIX.mapPoints(OFFSET_TEMP_FLOAT);
return (width - OFFSET_TEMP_FLOAT[0]) * (degrees > 0.0f ? 1.0f : -1.0f);
}
}
public class ZoomInTransformer extends ABaseTransformer {
@Override
protected void onTransform(View view, float position) {
final float scale = position < 0 ? position + 1f : Math.abs(1f - position);
view.setScaleX(scale);
view.setScaleY(scale);
view.setPivotX(view.getWidth() * 0.5f);
view.setPivotY(view.getHeight() * 0.5f);
view.setAlpha(position < -1f || position > 1f ? 0f : 1f - (scale - 1f));
}
}
public class ZoomOutSlideTransformer extends ABaseTransformer {
private static final float MIN_SCALE = 0.85f;
private static final float MIN_ALPHA = 0.5f;
@Override
protected void onTransform(View view, float position) {
if (position >= -1 || position <= 1) {
// Modify the default slide transition to shrink the page as well
final float height = view.getHeight();
final float scaleFactor = Math.max(MIN_SCALE, 1 - Math.abs(position));
final float vertMargin = height * (1 - scaleFactor) / 2;
final float horzMargin = view.getWidth() * (1 - scaleFactor) / 2;
// Center vertically
view.setPivotY(0.5f * height);
if (position < 0) {
view.setTranslationX(horzMargin - vertMargin / 2);
} else {
view.setTranslationX(-horzMargin + vertMargin / 2);
}
// Scale the page down (between MIN_SCALE and 1)
view.setScaleX(scaleFactor);
view.setScaleY(scaleFactor);
// Fade the page relative to its size.
view.setAlpha(MIN_ALPHA + (scaleFactor - MIN_SCALE) / (1 - MIN_SCALE) * (1 - MIN_ALPHA));
}
}
}
public class ZoomOutTranformer extends ABaseTransformer {
@Override
protected void onTransform(View view, float position) {
final float scale = 1f + Math.abs(position);
view.setScaleX(scale);
view.setScaleY(scale);
view.setPivotX(view.getWidth() * 0.5f);
view.setPivotY(view.getHeight() * 0.5f);
view.setAlpha(position < -1f || position > 1f ? 0f : 1f - (scale - 1f));
if(position == -1){
view.setTranslationX(view.getWidth() * -1);
}
}
}
具体效果,暂不上图了,更多效果 原
ViewPager切换动画