[转载]android-Viewpager – 一个人的ye – 博客频道 – CSDN.NET.
ViewPager是google SDk中自带的一个附加包的一个类(在Android-compatibility这个文件夹下),可以用来实现屏幕间的切换。
如可以仿一个workspace的效果。
Actviity:
import com.viewpagerindicator.CirclePageIndicator; import android.os.Bundle; import android.support.v4.app.FragmentActivity; import android.support.v4.view.ViewPager; public class ViewpagerActivity extends FragmentActivity { TestFragmentAdapter mAdapter; ViewPager mPager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //The look of this sample is set via a style in the manifest setContentView(R.layout.simple_circles); mAdapter = new TestFragmentAdapter(getSupportFragmentManager()); mPager = (ViewPager)findViewById(R.id.pager); mPager.setAdapter(mAdapter); CirclePageIndicator indicator = (CirclePageIndicator)findViewById(R.id.indicator); indicator.setViewPager(mPager); } }
simple_circles.xml:
<!--?xml version="1.0" encoding="utf-8"?-->
TestFragmentAdapter:
import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentPagerAdapter; class TestFragmentAdapter extends FragmentPagerAdapter { protected static final String[] CONTENT = new String[] { "第一页", "第二页", "第三页", "第四页", }; private int mCount = CONTENT.length; public TestFragmentAdapter(FragmentManager fm) { super(fm); } @Override public Fragment getItem(int position) { return TestFragment.newInstance(CONTENT[position % CONTENT.length]); } @Override public int getCount() { return mCount; } public void setCount(int count) { if (count > 0 && count <= 10) { mCount = count; notifyDataSetChanged(); } } }
TestFragment:
package com.shao.pager; import android.os.Bundle; import android.support.v4.app.Fragment; import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.LinearLayout; import android.widget.LinearLayout.LayoutParams; import android.widget.TextView; public final class TestFragment extends Fragment { private static final String KEY_CONTENT = "TestFragment:Content"; public static TestFragment newInstance(String content) { TestFragment fragment = new TestFragment(); fragment.mContent = content; return fragment; } private String mContent = "???"; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { if ((savedInstanceState != null) && savedInstanceState.containsKey(KEY_CONTENT)) { mContent = savedInstanceState.getString(KEY_CONTENT); } TextView text = new TextView(getActivity()); text.setGravity(Gravity.CENTER); text.setText(mContent); text.setTextSize(20 * getResources().getDisplayMetrics().density); text.setPadding(20, 20, 20, 20); LinearLayout layout = new LinearLayout(getActivity()); layout.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT)); layout.setGravity(Gravity.CENTER); layout.addView(text); return layout; } @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putString(KEY_CONTENT, mContent); } }
PageIndicator:
package com.viewpagerindicator; import android.support.v4.view.ViewPager; public interface PageIndicator extends ViewPager.OnPageChangeListener { public void setViewPager(ViewPager view); public void setViewPager(ViewPager view, int initialPosition); public void setCurrentItem(int item); public void setOnPageChangeListener(ViewPager.OnPageChangeListener listener); }
CliclePageIndicator:
package com.viewpagerindicator; import android.content.Context; import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Paint.Style; import android.os.Parcel; import android.os.Parcelable; import android.support.v4.view.ViewPager; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import com.shao.pager.R; public class CirclePageIndicator extends View implements PageIndicator { public static final int HORIZONTAL = 0; public static final int VERTICAL = 1; private float mRadius; private final Paint mPaintStroke; private final Paint mPaintFill; private ViewPager mViewPager; private ViewPager.OnPageChangeListener mListener; private int mCurrentPage; private int mSnapPage; private int mCurrentOffset; private int mScrollState; private int mPageSize; private int mOrientation; private boolean mCentered; private boolean mSnap; public CirclePageIndicator(Context context) { this(context, null); } public CirclePageIndicator(Context context, AttributeSet attrs) { this(context, attrs, R.attr.circlePageIndicatorStyle); } public CirclePageIndicator(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); //Load defaults from resources final Resources res = getResources(); final int defaultFillColor = res.getColor(R.color.default_circle_indicator_fill_color); final int defaultOrientation = res.getInteger(R.integer.default_circle_indicator_orientation); final int defaultStrokeColor = res.getColor(R.color.default_circle_indicator_stroke_color); final float defaultStrokeWidth = res.getDimension(R.dimen.default_circle_indicator_stroke_width); final float defaultRadius = res.getDimension(R.dimen.default_circle_indicator_radius); final boolean defaultCentered = res.getBoolean(R.bool.default_circle_indicator_centered); final boolean defaultSnap = res.getBoolean(R.bool.default_circle_indicator_snap); //Retrieve styles attributes TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CirclePageIndicator, defStyle, R.style.Widget_CirclePageIndicator); mCentered = a.getBoolean(R.styleable.CirclePageIndicator_centered, defaultCentered); mOrientation = a.getInt(R.styleable.CirclePageIndicator_orientation, defaultOrientation); mPaintStroke = new Paint(Paint.ANTI_ALIAS_FLAG); mPaintStroke.setStyle(Style.STROKE); mPaintStroke.setColor(a.getColor(R.styleable.CirclePageIndicator_strokeColor, defaultStrokeColor)); mPaintStroke.setStrokeWidth(a.getDimension(R.styleable.CirclePageIndicator_strokeWidth, defaultStrokeWidth)); mPaintFill = new Paint(Paint.ANTI_ALIAS_FLAG); mPaintFill.setStyle(Style.FILL); mPaintFill.setColor(a.getColor(R.styleable.CirclePageIndicator_fillColor, defaultFillColor)); mRadius = a.getDimension(R.styleable.CirclePageIndicator_radius, defaultRadius); mSnap = a.getBoolean(R.styleable.CirclePageIndicator_snap, defaultSnap); a.recycle(); } public void setCentered(boolean centered) { mCentered = centered; invalidate(); } public boolean isCentered() { return mCentered; } public void setFillColor(int fillColor) { mPaintFill.setColor(fillColor); invalidate(); } public int getFillColor() { return mPaintFill.getColor(); } public void setOrientation(int orientation) { switch (orientation) { case HORIZONTAL: case VERTICAL: mOrientation = orientation; updatePageSize(); requestLayout(); break; default: throw new IllegalArgumentException("Orientation must be either HORIZONTAL or VERTICAL."); } } public int getOrientation() { return mOrientation; } public void setStrokeColor(int strokeColor) { mPaintStroke.setColor(strokeColor); invalidate(); } public int getStrokeColor() { return mPaintStroke.getColor(); } public void setStrokeWidth(float strokeWidth) { mPaintStroke.setStrokeWidth(strokeWidth); invalidate(); } public float getStrokeWidth() { return mPaintStroke.getStrokeWidth(); } public void setRadius(float radius) { mRadius = radius; invalidate(); } public float getRadius() { return mRadius; } public void setSnap(boolean snap) { mSnap = snap; invalidate(); } public boolean isSnap() { return mSnap; } /* * (non-Javadoc) * * @see android.view.View#onDraw(android.graphics.Canvas) */ @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); int longSize; int longPaddingBefore; int longPaddingAfter; int shortPaddingBefore; if (mOrientation == HORIZONTAL) { longSize = getWidth(); longPaddingBefore = getPaddingLeft(); longPaddingAfter = getPaddingRight(); shortPaddingBefore = getPaddingTop(); } else { longSize = getHeight(); longPaddingBefore = getPaddingTop(); longPaddingAfter = getPaddingBottom(); shortPaddingBefore = getPaddingLeft(); } final int count = mViewPager.getAdapter().getCount(); final float threeRadius = mRadius * 3; final float shortOffset = shortPaddingBefore + mRadius; float longOffset = longPaddingBefore + mRadius; if (mCentered) { longOffset += ((longSize - longPaddingBefore - longPaddingAfter) / 2.0f) - ((count * threeRadius) / 2.0f); } float dX; float dY; //Draw stroked circles for (int iLoop = 0; iLoop < count; iLoop++) { float drawLong = longOffset + (iLoop * threeRadius); if (mOrientation == HORIZONTAL) { dX = drawLong; dY = shortOffset; } else { dX = shortOffset; dY = drawLong; } canvas.drawCircle(dX, dY, mRadius, mPaintStroke); } //Draw the filled circle according to the current scroll float cx = (mSnap ? mSnapPage : mCurrentPage) * threeRadius; if (!mSnap && (mPageSize != 0)) { cx += (mCurrentOffset * 1.0f / mPageSize) * threeRadius; } if (mOrientation == HORIZONTAL) { dX = longOffset + cx; dY = shortOffset; } else { dX = shortOffset; dY = longOffset + cx; } canvas.drawCircle(dX, dY, mRadius, mPaintFill); } @Override public boolean onTouchEvent(MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN) { final int count = mViewPager.getAdapter().getCount(); final int longSize = (mOrientation == HORIZONTAL) ? getWidth() : getHeight(); final float halfLongSize = longSize / 2; final float halfCircleLongSize = (count * 3 * mRadius) / 2; final float pointerValue = (mOrientation == HORIZONTAL) ? event.getX() : event.getY(); if ((mCurrentPage > 0) && (pointerValue < halfLongSize - halfCircleLongSize)) { setCurrentItem(mCurrentPage - 1); return true; } else if ((mCurrentPage < count - 1) && (pointerValue > halfLongSize + halfCircleLongSize)) { setCurrentItem(mCurrentPage + 1); return true; } } return super.onTouchEvent(event); } @Override public void setViewPager(ViewPager view) { if (view.getAdapter() == null) { throw new IllegalStateException("ViewPager does not have adapter instance."); } mViewPager = view; mViewPager.setOnPageChangeListener(this); updatePageSize(); invalidate(); } private void updatePageSize() { if (mViewPager != null) { mPageSize = (mOrientation == HORIZONTAL) ? mViewPager.getWidth() : mViewPager.getHeight(); } } @Override public void setViewPager(ViewPager view, int initialPosition) { setViewPager(view); setCurrentItem(initialPosition); } @Override public void setCurrentItem(int item) { if (mViewPager == null) { throw new IllegalStateException("ViewPager has not been bound."); } mViewPager.setCurrentItem(item); mCurrentPage = item; invalidate(); } @Override public void onPageScrollStateChanged(int state) { mScrollState = state; if (mListener != null) { mListener.onPageScrollStateChanged(state); } } @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { mCurrentPage = position; mCurrentOffset = positionOffsetPixels; updatePageSize(); invalidate(); if (mListener != null) { mListener.onPageScrolled(position, positionOffset, positionOffsetPixels); } } @Override public void onPageSelected(int position) { if (mSnap || mScrollState == ViewPager.SCROLL_STATE_IDLE) { mCurrentPage = position; mSnapPage = position; invalidate(); } if (mListener != null) { mListener.onPageSelected(position); } } @Override public void setOnPageChangeListener(ViewPager.OnPageChangeListener listener) { mListener = listener; } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { if (mOrientation == HORIZONTAL) { setMeasuredDimension(measureLong(widthMeasureSpec), measureShort(heightMeasureSpec)); } else { setMeasuredDimension(measureShort(widthMeasureSpec), measureLong(heightMeasureSpec)); } } /** * Determines the width of this view * * @param measureSpec * A measureSpec packed into an int * @return The width of the view, honoring constraints from measureSpec */ private int measureLong(int measureSpec) { int result = 0; int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); if (specMode == MeasureSpec.EXACTLY) { //We were told how big to be result = specSize; } else { //Calculate the width according the views count final int count = mViewPager.getAdapter().getCount(); result = (int)(getPaddingLeft() + getPaddingRight() + (count * 2 * mRadius) + (count - 1) * mRadius + 1); //Respect AT_MOST value if that was what is called for by measureSpec if (specMode == MeasureSpec.AT_MOST) { result = Math.min(result, specSize); } } return result; } private int measureShort(int measureSpec) { int result = 0; int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); if (specMode == MeasureSpec.EXACTLY) { //We were told how big to be result = specSize; } else { //Measure the height result = (int)(2 * mRadius + getPaddingTop() + getPaddingBottom() + 1); //Respect AT_MOST value if that was what is called for by measureSpec if (specMode == MeasureSpec.AT_MOST) { result = Math.min(result, specSize); } } return result; } @Override public void onRestoreInstanceState(Parcelable state) { SavedState savedState = (SavedState)state; super.onRestoreInstanceState(savedState.getSuperState()); mCurrentPage = savedState.currentPage; mSnapPage = savedState.currentPage; requestLayout(); } @Override public Parcelable onSaveInstanceState() { Parcelable superState = super.onSaveInstanceState(); SavedState savedState = new SavedState(superState); savedState.currentPage = mCurrentPage; return savedState; } static class SavedState extends BaseSavedState { int currentPage; public SavedState(Parcelable superState) { super(superState); } private SavedState(Parcel in) { super(in); currentPage = in.readInt(); } @Override public void writeToParcel(Parcel dest, int flags) { super.writeToParcel(dest, flags); dest.writeInt(currentPage); } public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { @Override public SavedState createFromParcel(Parcel in) { return new SavedState(in); } @Override public SavedState[] newArray(int size) { return new SavedState[size]; } }; } }