横向和纵向的ViewPage,引导页

转载请注明出处:  http://blog.youkuaiyun.com/forwardyzk/article/details/42780427

我们看到的应用引导页有横向滑动和纵向滑动的,横向的我们很好实现,使用ViewPager即可,如果是纵向的,ViewPager设置纵向的功能,所以我们需要自定义纵向的ViewPager,下面为大家通过一款既可以横向也可以纵向的ViewPager。



使用了自定义属性:

自定义类ViewPager继承ViewGroup

<span style="font-family:SimSun;font-size:18px;">TypedArray a = context.obtainStyledAttributes(attrs,
				R.styleable.ViewPager, defStyle, 0);
		mOrientation = a.getInt(R.styleable.ViewPager_orientation,
				ORIENTATION_HORIZONTAL);</span>

获取自定义方向属性对应的值,默认的为横向的。

<span style="font-family:SimSun;font-size:18px;">public boolean isOrientationHorizontal() {
		return mOrientation == ORIENTATION_HORIZONTAL;
	}</span>

判断是是否是横向的,否则就是纵向的。

在onMeasure方法中对其所有的子孩子进行测量长和宽,

通过循环遍历所有的子孩子

<span style="font-family:SimSun;font-size:18px;">final int widthSpec = MeasureSpec.makeMeasureSpec(
							widthSize, widthMode);
					final int heightSpec = MeasureSpec.makeMeasureSpec(
							heightSize, heightMode);
					child.measure(widthSpec, heightSpec);

					if (consumeVertical) {
						childHeightSize -= child.getMeasuredHeight();
					} else if (consumeHorizontal) {
						childWidthSize -= child.getMeasuredWidth();
					}</span>

同时也要准备显示的item显示的滑动的方向

<span style="font-family:SimSun;font-size:18px;">int focusDirection = View.FOCUS_FORWARD;
		if (mCurItem != newCurrentItem) {
			if (isOrientationHorizontal()) {
				focusDirection = mCurItem < newCurrentItem ? View.FOCUS_RIGHT
						: View.FOCUS_LEFT;
			} else {
				focusDirection = mCurItem < newCurrentItem ? View.FOCUS_DOWN
						: View.FOCUS_UP;
			}
			oldCurInfo = infoForPosition(mCurItem);
			mCurItem = newCurrentItem;
		}</span>

在onLayout显示的位置

<span style="font-family:SimSun;font-size:18px;">switch (hgrav) {
					default:
						childLeft = paddingLeft;
						break;
					case Gravity.LEFT:
						childLeft = paddingLeft;
						paddingLeft += child.getMeasuredWidth();
						break;
					case Gravity.CENTER_HORIZONTAL:
						childLeft = Math.max(
								(width - child.getMeasuredWidth()) / 2,
								paddingLeft);
						break;
					case Gravity.RIGHT:
						childLeft = width - paddingRight
								- child.getMeasuredWidth();
						paddingRight += child.getMeasuredWidth();
						break;
					}
					switch (vgrav) {
					default:
						childTop = paddingTop;
						break;
					case Gravity.TOP:
						childTop = paddingTop;
						paddingTop += child.getMeasuredHeight();
						break;
					case Gravity.CENTER_VERTICAL:
						childTop = Math.max(
								(height - child.getMeasuredHeight()) / 2,
								paddingTop);
						break;
					case Gravity.BOTTOM:
						childTop = height - paddingBottom
								- child.getMeasuredHeight();
						paddingBottom += child.getMeasuredHeight();
						break;
					}
					if (isOrientationHorizontal()) {
						childLeft += scrollX;
					} else {
						childTop += scrollY;
					}
					child.layout(childLeft, childTop,
							childLeft + child.getMeasuredWidth(), childTop
									+ child.getMeasuredHeight());
					decorCount++;
				}
			}
		}</span>

根据设置的Gravity,要计算其当前显示的间距,根据设置的方向和滑动的距离(scrollX),计算其不断的更改其位置(child.layout)。


在onTouchEvent()会根据手势点击状态,向外传递当前的状态。

<span style="font-family:SimSun;font-size:18px;">case MotionEvent.ACTION_DOWN: {
			mScroller.abortAnimation();
			mPopulatePending = false;
			populate();
			mIsBeingDragged = true;
			setScrollState(SCROLL_STATE_DRAGGING);

			// Remember where the motion event started
			mLastMotionX = mInitialMotionX = ev.getX();
			mLastMotionY = mInitialMotionY = ev.getY();
			mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
			break;
		}
		case MotionEvent.ACTION_MOVE:
			if (!mIsBeingDragged) {
				final int pointerIndex = MotionEventCompat.findPointerIndex(ev,
						mActivePointerId);
				final float x = MotionEventCompat.getX(ev, pointerIndex);
				final float xDiff = Math.abs(x - mLastMotionX);
				final float y = MotionEventCompat.getY(ev, pointerIndex);
				final float yDiff = Math.abs(y - mLastMotionY);
				if (DEBUG)
					Log.v(TAG, "Moved x to " + x + "," + y + " diff=" + xDiff
							+ "," + yDiff);
				if (isOrientationHorizontal()) {
					if (xDiff > mTouchSlop && xDiff > yDiff) {
						if (DEBUG)
							Log.v(TAG, "Starting drag!");
						mIsBeingDragged = true;
						mLastMotionX = x - mInitialMotionX > 0 ? mInitialMotionX
								+ mTouchSlop
								: mInitialMotionX - mTouchSlop;
						mLastMotionY = y;
						setScrollState(SCROLL_STATE_DRAGGING);
						setScrollingCacheEnabled(true);
					}
				} else {
					if (yDiff > mTouchSlop && yDiff > xDiff) {
						if (DEBUG)
							Log.v(TAG, "Starting drag!");
						mIsBeingDragged = true;
						mLastMotionY = y - mInitialMotionY > 0 ? mInitialMotionY
								+ mTouchSlop
								: mInitialMotionY - mTouchSlop;
						mLastMotionX = x;
						setScrollState(SCROLL_STATE_DRAGGING);
						setScrollingCacheEnabled(true);
					}
				}
			}
			// Not else! Note that mIsBeingDragged can be set above.
			if (mIsBeingDragged) {
				// Scroll to follow the motion event
				final int activePointerIndex = MotionEventCompat
						.findPointerIndex(ev, mActivePointerId);
				float x = 0;
				if (isOrientationHorizontal()) {
					x = MotionEventCompat.getX(ev, activePointerIndex);
				} else {
					x = MotionEventCompat.getY(ev, activePointerIndex);
				}
				needsInvalidate |= performDrag(x);
			}
			break;</span>

当离开屏幕时,MotionEvent.ACTION_UP,需要判断需要显示的item, setCurrentItemInternal(nextPage, true, true, initialVelocity);

会有这样的看出,进行位置的滑动,

<span style="font-family:SimSun;font-size:18px;">populate(item);
			scrollToItem(item, smoothScroll, velocity, dispatchSelected);</span>

当屏幕改变的时,来保证当前显示的item始终正确,

<span style="font-family:SimSun;font-size:18px;">protected void onSizeChanged(int w, int h, int oldw, int oldh) {
		super.onSizeChanged(w, h, oldw, oldh);

		// Make sure scroll position is set correctly.
		if (w != oldw) {
			recomputeScrollPosition(w, oldw, h, oldh, mPageMargin, mPageMargin);
		}
	}</span>
在computeScroll()处理mScroller手势的滑动,来改变位置的移动当前ViewPager(即ViewGroup)的移动

<span style="font-family:SimSun;font-size:18px;">public void computeScroll() {
		if (!mScroller.isFinished() && mScroller.computeScrollOffset()) {
			int oldX = getScrollX();
			int oldY = getScrollY();
			int x = mScroller.getCurrX();
			int y = mScroller.getCurrY();

			if (oldX != x || oldY != y) {
				scrollTo(x, y);
				if (!pageScrolled(isOrientationHorizontal() ? x : y)) {
					mScroller.abortAnimation();
					if (isOrientationHorizontal()) {
						scrollTo(0, y);
					} else {
						scrollTo(x, 0);
					}
				}
			}

			// Keep on drawing until the animation has finished.
			ViewCompat.postInvalidateOnAnimation(this);
			return;
		}

		// Done with scroll, clean up state.
		completeScroll(true);
	}</span>

设置选中的item

<span style="font-family:SimSun;font-size:18px;">protected void onPageScrolled(int position, float offset, int offsetPixels) {
		// Offset any decor views if needed - keep them on-screen at all times.
		if (mDecorChildCount > 0) {
			// TODO This is where I start getting tired. Refactor this better
			// later.
			if (isOrientationHorizontal()) {
				final int scrollX = getScrollX();
				int paddingLeft = getPaddingLeft();
				int paddingRight = getPaddingRight();
				final int width = getWidth();
				final int childCount = getChildCount();
				for (int i = 0; i < childCount; i++) {
					final View child = getChildAt(i);
					final LayoutParams lp = (LayoutParams) child
							.getLayoutParams();
					if (!lp.isDecor)
						continue;

					final int hgrav = lp.gravity
							& Gravity.HORIZONTAL_GRAVITY_MASK;
					int childLeft = 0;
					switch (hgrav) {
					default:
						childLeft = paddingLeft;
						break;
					case Gravity.LEFT:
						childLeft = paddingLeft;
						paddingLeft += child.getWidth();
						break;
					case Gravity.CENTER_HORIZONTAL:
						childLeft = Math.max(
								(width - child.getMeasuredWidth()) / 2,
								paddingLeft);
						break;
					case Gravity.RIGHT:
						childLeft = width - paddingRight
								- child.getMeasuredWidth();
						paddingRight += child.getMeasuredWidth();
						break;
					}
					childLeft += scrollX;

					final int childOffset = childLeft - child.getLeft();
					if (childOffset != 0) {
						child.offsetLeftAndRight(childOffset);
					}
				}
			} else {
				final int scrollY = getScrollY();
				int paddingTop = getPaddingTop();
				int paddingBottom = getPaddingBottom();
				final int height = getHeight();
				final int childCount = getChildCount();
				for (int i = 0; i < childCount; i++) {
					final View child = getChildAt(i);
					final LayoutParams lp = (LayoutParams) child
							.getLayoutParams();
					if (!lp.isDecor)
						continue;

					final int vgrav = lp.gravity
							& Gravity.VERTICAL_GRAVITY_MASK;
					int childTop = 0;
					switch (vgrav) {
					default:
						childTop = paddingTop;
						break;
					case Gravity.TOP:
						childTop = paddingTop;
						paddingTop += child.getHeight();
						break;
					case Gravity.CENTER_VERTICAL:
						childTop = Math.max(
								(height - child.getMeasuredHeight()) / 2,
								paddingTop);
						break;
					case Gravity.BOTTOM:
						childTop = height - paddingBottom
								- child.getMeasuredHeight();
						paddingBottom += child.getMeasuredHeight();
						break;
					}
					childTop += scrollY;

					final int childOffset = childTop - child.getTop();
					if (childOffset != 0) {
						child.offsetTopAndBottom(childOffset);
					}
				}
			}
		}

		if (mOnPageChangeListener != null) {
			mOnPageChangeListener
					.onPageScrolled(position, offset, offsetPixels);
		}
		if (mInternalPageChangeListener != null) {
			mInternalPageChangeListener.onPageScrolled(position, offset,
					offsetPixels);
		}

		if (mPageTransformer != null) {
			final boolean horizontal = isOrientationHorizontal();
			final int scroll = horizontal ? getScrollX() : getScrollY();
			final int childCount = getChildCount();
			for (int i = 0; i < childCount; i++) {
				final View child = getChildAt(i);
				final LayoutParams lp = (LayoutParams) child.getLayoutParams();

				if (lp.isDecor)
					continue;

				float transformPos;
				if (horizontal) {
					transformPos = (float) (child.getLeft() - scroll)
							/ getClientWidth();
				} else {
					transformPos = (float) (child.getTop() - scroll)
							/ getClientHeight();
				}
				mPageTransformer.transformPage(child, transformPos);
			}
		}

		mCalledSuper = true;
	}</span>


使用步骤:

activity_main.xml

<span style="font-family:SimSun;font-size:18px;"><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <com.ryanharter.viewpager.ViewPager
        android:id="@+id/pager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:orientation="vertical" >
    </com.ryanharter.viewpager.ViewPager>

</RelativeLayout></span>

因为使用了自定义属性,所以要在xml的根节点下添加 xmlns:app="http://schemas.android.com/apk/res-auto"

设置app:orientation="vertical"或者horizontal


MainActivity.java

<span style="font-family:SimSun;font-size:18px;">public class MainActivity extends Activity {

	private ViewPager pager;
	private List<View> pagerViews;
	private Context mContext;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		mContext = MainActivity.this;
		initView();
		initPagerViews();
		initData();
	}

	private void initData() {
		pager.setAdapter(new MyAdapter());
		pager.setOnPageChangeListener(new OnPageChangeListener() {

			@Override
			public void onPageSelected(int position) {
				Toast.makeText(getApplicationContext(), "选中了" + position, 0)
						.show();
			}

			@Override
			public void onPageScrolled(int position, float positionOffset,
					int positionOffsetPixels) {

			}

			@Override
			public void onPageScrollStateChanged(int state) {

			}
		});
	}

	private void initPagerViews() {
		pagerViews = new ArrayList<View>();
		LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT,
				LayoutParams.MATCH_PARENT);
		TextView tv = null;

		for (int i = 0; i < 4; i++) {
			tv = new TextView(mContext);
			tv.setText("View--" + i);
			tv.setLayoutParams(lp);
			tv.setGravity(Gravity.CENTER);
			if (i == 0) {
				tv.setBackgroundColor(mContext.getResources().getColor(
						android.R.color.holo_blue_bright));
			} else if (i == 1) {
				tv.setBackgroundColor(mContext.getResources().getColor(
						android.R.color.holo_green_dark));
			} else if (i == 2) {

				tv.setBackgroundColor(mContext.getResources().getColor(
						android.R.color.holo_orange_light));
			} else if (i == 3) {
				tv.setBackgroundColor(mContext.getResources().getColor(
						android.R.color.holo_red_dark));
			}
			pagerViews.add(tv);
		}
	}

	private void initView() {
		pager = (ViewPager) findViewById(R.id.pager);

	}

	class MyAdapter extends PagerAdapter {

		@Override
		public int getCount() {
			if (pagerViews == null)
				return 0;
			else
				return pagerViews.size();
		}

		@Override
		public boolean isViewFromObject(View arg0, Object arg1) {
			return arg0 == arg1;
		}

		@Override
		public void destroyItem(ViewGroup container, int position, Object object) {
			// super.destroyItem(container, position, object);
			container.removeView((View) object);
		}

		@Override
		public Object instantiateItem(ViewGroup container, int position) {
			container.addView(pagerViews.get(position));
			return pagerViews.get(position);
			// return super.instantiateItem(container, position);
		}
	}

}
</span>


使用的Viewpager,PagerAdapter和OnPageChangeListener是

import com.ryanharter.viewpager.PagerAdapter;
import com.ryanharter.viewpager.ViewPager;
import com.ryanharter.viewpager.ViewPager.OnPageChangeListener;

包中的。

源码下载: http://download.youkuaiyun.com/detail/forwardyzk/8375173

效果图:







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值