如何在Xamarin.Android中使用Dot Sliders实现ViewPagers?

时间:2017-04-18 05:18:24

标签: xamarin.android

我最近正在学习Xamarin.Android,我试图用最后几天的实践来实现带有点滑块的页面浏览器,但未能实现它,我已经从stackoverflow和github这样的流行集线器中引用了很多解决方案但是没有做到所以。 任何人都可以解释一下如何在xamarin.android中使用点滑块实现viewpagers。 我正在附上一张照片供您参考,这可以让您清楚地了解我的要求。enter image description here

你可以看到他正在使用我试图这样做的点滑块来滑动页面。 请解释我如何在Xamarin.Android(Native)

中做到这一点

3 个答案:

答案 0 :(得分:1)

首先定义您自己的自定义圈子页面 - 指示器让它为CirclePageIndicator.cs将其添加到您的项目(而不是活动文件) 使用Android.Content;

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.Graphics;
using Android.Support.V4.View;
using Android.Util;
using Java.Lang;
using Java.Interop;


namespace MyApplication.Droid.Library
{
    public class CirclePageIndicator : View,PageIndicator
    {
        const int HORIZONTAL = 0;
        const int VERTICAL = 1;
        private float mRadius;
        private Paint mPaintPageFill;
        private Paint mPaintStroke;
        private Paint mPaintFill;
        private ViewPager mViewPager;
        private ViewPager.IOnPageChangeListener mListener;
        private int mCurrentPage;
        private int mSnapPage;
        private int mCurrentOffset;
        private int mScrollState;
        private int mPageSize;
        private int mOrientation;
        private bool mCentered;
        private bool mSnap;
        private const int INVALID_POINTER = -1;
        private int mTouchSlop;
        private float mLastMotionX = -1;
        private int mActivePointerId = INVALID_POINTER;
        private bool mIsDragging;

        public CirclePageIndicator(Context context) : this(context, null)
        {
        }

        public CirclePageIndicator(Context context, IAttributeSet attrs) : this(context, attrs, Resource.Attribute.vpiCirclePageIndicatorStyle)
        {
        }

        public CirclePageIndicator(Context context, IAttributeSet attrs, int defStyle) : base(context, attrs, defStyle)
        {
            //Load defaults from resources
            var res = Resources;
            int defaultPageColor = res.GetColor(Resource.Color.default_circle_indicator_page_color);
            int defaultFillColor = res.GetColor(Resource.Color.default_circle_indicator_fill_color);
            int defaultOrientation = res.GetInteger(Resource.Integer.default_circle_indicator_orientation);
            int defaultStrokeColor = res.GetColor(Resource.Color.default_circle_indicator_stroke_color);
            float defaultStrokeWidth = res.GetDimension(Resource.Dimension.default_circle_indicator_stroke_width);
            float defaultRadius = res.GetDimension(Resource.Dimension.default_circle_indicator_radius);
            bool defaultCentered = res.GetBoolean(Resource.Boolean.default_circle_indicator_centered);
            bool defaultSnap = res.GetBoolean(Resource.Boolean.default_circle_indicator_snap);

            //Retrieve styles attributes
            var a = context.ObtainStyledAttributes(attrs, Resource.Styleable.CirclePageIndicator, defStyle, Resource.Style.Widget_CirclePageIndicator);

            mCentered = a.GetBoolean(Resource.Styleable.CirclePageIndicator_centered, defaultCentered);
            mOrientation = a.GetInt(Resource.Styleable.CirclePageIndicator_orientation, defaultOrientation);
            mPaintPageFill = new Paint(PaintFlags.AntiAlias);
            mPaintPageFill.SetStyle(Paint.Style.Fill);
            mPaintPageFill.Color = a.GetColor(Resource.Styleable.CirclePageIndicator_pageColor, defaultPageColor);
            mPaintStroke = new Paint(PaintFlags.AntiAlias);
            mPaintStroke.SetStyle(Paint.Style.Stroke);
            mPaintStroke.Color = a.GetColor(Resource.Styleable.CirclePageIndicator_strokeColor, defaultStrokeColor);
            mPaintStroke.StrokeWidth = a.GetDimension(Resource.Styleable.CirclePageIndicator_strokeWidth, defaultStrokeWidth);
            mPaintFill = new Paint(PaintFlags.AntiAlias);
            mPaintFill.SetStyle(Paint.Style.Fill);
            mPaintFill.Color = a.GetColor(Resource.Styleable.CirclePageIndicator_fillColor, defaultFillColor);
            mRadius = a.GetDimension(Resource.Styleable.CirclePageIndicator_radius, defaultRadius);
            mSnap = a.GetBoolean(Resource.Styleable.CirclePageIndicator_snap, defaultSnap);

            a.Recycle();

            var configuration = ViewConfiguration.Get(context);
            mTouchSlop = ViewConfigurationCompat.GetScaledPagingTouchSlop(configuration);

        }

        public void SetCentered(bool centered)
        {
            mCentered = centered;
            Invalidate();
        }

        public bool IsCentered()
        {
            return mCentered;
        }

        public void SetPageColor(Color pageColor)
        {
            mPaintPageFill.Color = pageColor;
            Invalidate();
        }

        public int GetPageColor()
        {
            return mPaintPageFill.Color;
        }

        public void SetFillColor(Color fillColor)
        {
            mPaintFill.Color = fillColor;
            Invalidate();
        }

        public int GetFillColor()
        {
            return mPaintFill.Color;
        }

        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(Color strokeColor)
        {
            mPaintStroke.Color = strokeColor;
            Invalidate();
        }

        public int GetStrokeColor()
        {
            return mPaintStroke.Color;
        }

        public void SetStrokeWidth(float strokeWidth)
        {
            mPaintStroke.StrokeWidth = strokeWidth;
            Invalidate();
        }

        public float GetStrokeWidth()
        {
            return mPaintStroke.StrokeWidth;
        }

        public void SetRadius(float radius)
        {
            mRadius = radius;
            Invalidate();
        }

        public float GetRadius()
        {
            return mRadius;
        }

        public void SetSnap(bool snap)
        {
            mSnap = snap;
            Invalidate();
        }

        public bool IsSnap()
        {
            return mSnap;
        }

        protected override void OnDraw(Canvas canvas)
        {
            base.OnDraw(canvas);

            if (mViewPager == null)
            {
                return;
            }
            int count = mViewPager.Adapter.Count;
            if (count == 0)
            {
                return;
            }

            if (mCurrentPage >= count)
            {
                SetCurrentItem(count - 1);
                return;
            }

            int longSize;
            int longPaddingBefore;
            int longPaddingAfter;
            int shortPaddingBefore;
            if (mOrientation == HORIZONTAL)
            {
                longSize = Width;
                longPaddingBefore = PaddingLeft;
                longPaddingAfter = PaddingRight;
                shortPaddingBefore = PaddingTop;
            }
            else
            {
                longSize = Height;
                longPaddingBefore = PaddingTop;
                longPaddingAfter = PaddingBottom;
                shortPaddingBefore = PaddingLeft;
            }

            float threeRadius = mRadius * 3;
            float shortOffset = shortPaddingBefore + mRadius;
            float longOffset = longPaddingBefore + mRadius;
            if (mCentered)
            {
                longOffset += ((longSize - longPaddingBefore - longPaddingAfter) / 2.0f) - ((count * threeRadius) / 2.0f);
            }

            float dX;
            float dY;

            float pageFillRadius = mRadius;
            if (mPaintStroke.StrokeWidth > 0)
            {
                pageFillRadius -= mPaintStroke.StrokeWidth / 2.0f;
            }

            //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;
                }
                // Only paint fill if not completely transparent
                if (mPaintPageFill.Alpha > 0)
                {
                    canvas.DrawCircle(dX, dY, pageFillRadius, mPaintPageFill);
                }

                // Only paint stroke if a stroke width was non-zero
                if (pageFillRadius != mRadius)
                {
                    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);
        }

        public override bool OnTouchEvent(MotionEvent ev)
        {

            if (base.OnTouchEvent(ev))
            {
                return true;
            }
            if ((mViewPager == null) || (mViewPager.Adapter.Count == 0))
            {
                return false;
            }

            var action = ev.Action;

            switch ((int)action & MotionEventCompat.ActionMask)
            {
                case (int)MotionEventActions.Down:
                    mActivePointerId = MotionEventCompat.GetPointerId(ev, 0);
                    mLastMotionX = ev.GetX();
                    break;

                case (int)MotionEventActions.Move:
                    {
                        int activePointerIndex = MotionEventCompat.FindPointerIndex(ev, mActivePointerId);
                        float x = MotionEventCompat.GetX(ev, activePointerIndex);
                        float deltaX = x - mLastMotionX;

                        if (!mIsDragging)
                        {
                            if (Java.Lang.Math.Abs(deltaX) > mTouchSlop)
                            {
                                mIsDragging = true;
                            }
                        }

                        if (mIsDragging)
                        {
                            if (!mViewPager.IsFakeDragging)
                            {
                                mViewPager.BeginFakeDrag();
                            }

                            mLastMotionX = x;

                            mViewPager.FakeDragBy(deltaX);
                        }

                        break;
                    }

                case (int)MotionEventActions.Cancel:
                case (int)MotionEventActions.Up:
                    if (!mIsDragging)
                    {
                        int count = mViewPager.Adapter.Count;
                        int width = Width;
                        float halfWidth = width / 2f;
                        float sixthWidth = width / 6f;

                        if ((mCurrentPage > 0) && (ev.GetX() < halfWidth - sixthWidth))
                        {
                            mViewPager.CurrentItem = mCurrentPage - 1;
                            return true;
                        }
                        else if ((mCurrentPage < count - 1) && (ev.GetX() > halfWidth + sixthWidth))
                        {
                            mViewPager.CurrentItem = mCurrentPage + 1;
                            return true;
                        }
                    }

                    mIsDragging = false;
                    mActivePointerId = INVALID_POINTER;
                    if (mViewPager.IsFakeDragging)
                        mViewPager.EndFakeDrag();
                    break;

                case MotionEventCompat.ActionPointerDown:
                    {
                        int index = MotionEventCompat.GetActionIndex(ev);
                        float x = MotionEventCompat.GetX(ev, index);
                        mLastMotionX = x;
                        mActivePointerId = MotionEventCompat.GetPointerId(ev, index);
                        break;
                    }

                case MotionEventCompat.ActionPointerUp:
                    int pointerIndex = MotionEventCompat.GetActionIndex(ev);
                    int pointerId = MotionEventCompat.GetPointerId(ev, pointerIndex);
                    if (pointerId == mActivePointerId)
                    {
                        int newPointerIndex = pointerIndex == 0 ? 1 : 0;
                        mActivePointerId = MotionEventCompat.GetPointerId(ev, newPointerIndex);
                    }
                    mLastMotionX = MotionEventCompat.GetX(ev, MotionEventCompat.FindPointerIndex(ev, mActivePointerId));
                    break;
            }

            return true;
        }

        public void SetViewPager(ViewPager view)
        {
            if (view.Adapter == 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.Width : mViewPager.Height;
            }
        }

        public void SetViewPager(ViewPager view, int initialPosition)
        {
            SetViewPager(view);
            SetCurrentItem(initialPosition);
        }

        public void SetCurrentItem(int item)
        {
            if (mViewPager == null)
            {
                throw new IllegalStateException("ViewPager has not been bound.");
            }
            mViewPager.CurrentItem = item;
            mCurrentPage = item;
            Invalidate();
        }

        public void NotifyDataSetChanged()
        {
            Invalidate();
        }

        public void OnPageScrollStateChanged(int state)
        {
            mScrollState = state;

            if (mListener != null)
            {
                mListener.OnPageScrollStateChanged(state);
            }
        }

        public void OnPageScrolled(int position, float positionOffset, int positionOffsetPixels)
        {
            mCurrentPage = position;
            mCurrentOffset = positionOffsetPixels;
            UpdatePageSize();
            Invalidate();

            if (mListener != null)
            {
                mListener.OnPageScrolled(position, positionOffset, positionOffsetPixels);
            }
        }

        public void OnPageSelected(int position)
        {
            if (mSnap || mScrollState == ViewPager.ScrollStateIdle)
            {
                mCurrentPage = position;
                mSnapPage = position;
                Invalidate();
            }

            if (mListener != null)
            {
                mListener.OnPageSelected(position);
            }
        }

        public void SetOnPageChangeListener(ViewPager.IOnPageChangeListener listener)
        {
            mListener = listener;
        }

        protected override 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;
            var specMode = MeasureSpec.GetMode(measureSpec);
            var specSize = MeasureSpec.GetSize(measureSpec);

            if ((specMode == MeasureSpecMode.Exactly) || (mViewPager == null))
            {
                //We were told how big to be
                result = specSize;
            }
            else
            {
                //Calculate the width according the views count
                int count = mViewPager.Adapter.Count;
                result = (int)(PaddingLeft + PaddingRight
                        + (count * 2 * mRadius) + (count - 1) * mRadius + 1);
                //Respect AT_MOST value if that was what is called for by measureSpec
                if (specMode == MeasureSpecMode.AtMost)
                {
                    result = Java.Lang.Math.Min(result, specSize);
                }
            }
            return result;
        }

        /**
         * Determines the height of this view
         *
         * @param measureSpec
         *            A measureSpec packed into an int
         * @return The height of the view, honoring constraints from measureSpec
         */
        private int MeasureShort(int measureSpec)
        {
            int result = 0;
            var specMode = MeasureSpec.GetMode(measureSpec);
            var specSize = MeasureSpec.GetSize(measureSpec);

            if (specMode == MeasureSpecMode.Exactly)
            {
                //We were told how big to be
                result = specSize;
            }
            else
            {
                //Measure the height
                result = (int)(2 * mRadius + PaddingTop + PaddingBottom + 1);
                //Respect AT_MOST value if that was what is called for by measureSpec
                if (specMode == MeasureSpecMode.AtMost)
                {
                    result = Java.Lang.Math.Min(result, specSize);
                }
            }
            return result;
        }

        protected override void OnRestoreInstanceState(IParcelable state)
        {

            try
            {
                SavedState savedState = (SavedState)state;
                base.OnRestoreInstanceState(savedState.SuperState);
                mCurrentPage = savedState.CurrentPage;
                mSnapPage = savedState.CurrentPage;
            }
            catch
            {
                base.OnRestoreInstanceState(state);
                // Ignore, this needs to support IParcelable...
            }
            RequestLayout();
        }

        protected override IParcelable OnSaveInstanceState()
        {
            var superState = base.OnSaveInstanceState();
            var savedState = new SavedState(superState);
            savedState.CurrentPage = mCurrentPage;
            return savedState;
        }

        public class SavedState : BaseSavedState
        {
            public int CurrentPage { get; set; }

            public SavedState(IParcelable superState) : base(superState)
            {
            }

            private SavedState(Parcel parcel) : base(parcel)
            {
                CurrentPage = parcel.ReadInt();
            }

            public override void WriteToParcel(Parcel dest, ParcelableWriteFlags flags)
            {
                base.WriteToParcel(dest, flags);
                dest.WriteInt(CurrentPage);
            }

            [ExportField("CREATOR")]
            static SavedStateCreator InitializeCreator()
            {
                return new SavedStateCreator();
            }

            class SavedStateCreator : Java.Lang.Object, IParcelableCreator
            {
                public Java.Lang.Object CreateFromParcel(Parcel source)
                {
                    return new SavedState(source);
                }

                public Java.Lang.Object[] NewArray(int size)
                {
                    return new SavedState[size];
                }
            }
        }
    }
}

现在将PageIndicator.cs文件添加到项目(而不是活动文件)

using Android.Support.V4.View;

namespace MyApplication.Droid.Library
{
    public interface PageIndicator : ViewPager.IOnPageChangeListener
    {
        /**
         * Bind the indicator to a ViewPager.
         *
         * @param view
         */
        void SetViewPager(ViewPager view);

        /**
         * Bind the indicator to a ViewPager.
         *
         * @param view
         * @param initialPosition
         */
        void SetViewPager(ViewPager view, int initialPosition);

        /**
         * <p>Set the current page of both the ViewPager and indicator.</p>
         *
         * <p>This <strong>must</strong> be used if you need to set the page before
         * the views are drawn on screen (e.g., default start page).</p>
         *
         * @param item
         */
        void SetCurrentItem(int item);

        /**
         * Set a page change listener which will receive forwarded events.
         *
         * @param listener
         */
        void SetOnPageChangeListener(ViewPager.IOnPageChangeListener listener);

        /**
         * Notify the indicator that the fragment list has changed.
         */
        void NotifyDataSetChanged();
    }

}

现在将以下文件添加到您的值文件中: vpi__styles.xml

<?xml version="1.0" encoding="utf-8" ?>
<resources>
  <style name="Widget"></style>

  <style name="Widget.CirclePageIndicator" parent="Widget">
    <item name="centered">@bool/default_circle_indicator_centered</item>
    <item name="fillColor">@color/default_circle_indicator_fill_color</item>
    <item name="pageColor">@color/default_circle_indicator_page_color</item>
    <item name="orientation">@integer/default_circle_indicator_orientation</item>
    <item name="radius">@dimen/default_circle_indicator_radius</item>
    <item name="snap">@bool/default_circle_indicator_snap</item>
    <item name="strokeColor">@color/default_circle_indicator_stroke_color</item>
    <item name="strokeWidth">@dimen/default_circle_indicator_stroke_width</item>
  </style>
</resources>

vpi__defaults.xml

<?xml version="1.0" encoding="utf-8" ?>
<resources>
  <bool name="default_circle_indicator_centered">true</bool>
  <color name="default_circle_indicator_fill_color">#FFFFFFFF</color>
  <color name="default_circle_indicator_page_color">#00000000</color>
  <integer name="default_circle_indicator_orientation">0</integer>
  <dimen name="default_circle_indicator_radius">3dp</dimen>
  <bool name="default_circle_indicator_snap">false</bool>
  <color name="default_circle_indicator_stroke_color">#FFDDDDDD</color>
  <dimen name="default_circle_indicator_stroke_width">1dp</dimen>
</resources>

vpi__colors.xml

<?xml version="1.0" encoding="utf-8" ?>
<resources>
  <color name="vpi__background_holo_dark">#ff000000</color>
  <color name="vpi__background_holo_light">#fff3f3f3</color>
  <color name="vpi__bright_foreground_disabled_holo_dark">#ff4c4c4c</color>
  <color name="vpi__bright_foreground_disabled_holo_light">#ffb2b2b2</color>
</resources>

vpi__attrs.xml

<?xml version="1.0" encoding="utf-8" ?>
<resources>
  <declare-styleable name="ViewPagerIndicator">
    <!-- Style of the circle indicator. -->
    <attr name="vpiCirclePageIndicatorStyle" format="reference"/>
  </declare-styleable>
  <declare-styleable name="CirclePageIndicator">
    <!-- Whether or not the indicators should be centered. -->
    <attr name="centered" format="boolean" />
    <!-- Color of the filled circle that represents the current page. -->
    <attr name="fillColor" format="color" />
    <!-- Color of the filled circles that represents pages. -->
    <attr name="pageColor" format="color" />
    <!-- Orientation of the indicator. -->
    <attr name="orientation">
      <enum name="horizontal" value="0" />
      <enum name="vertical" value="1" />
    </attr>
    <!-- Radius of the circles. This is also the spacing between circles. -->
    <attr name="radius" format="dimension" />
    <!-- Whether or not the selected indicator snaps to the circles. -->
    <attr name="snap" format="boolean" />
    <!-- Color of the open circles. -->
    <attr name="strokeColor" format="color" />
    <!-- Width of the stroke used to draw the circles. -->
    <attr name="strokeWidth" format="dimension" />
  </declare-styleable>
</resources>

现在将此代码添加到设计文件中。 在这里你必须注意MyApplication.Droid.Library是我的名字空间而CirclePageIndicator是我的页面指示器文件名,所以用它的替换它

  <MyApplication.Droid.Library.CirclePageIndicator
      android:id="@+id/indicator"
      android:padding="10dip"
      android:layout_height="wrap_content"
      android:layout_width="fill_parent"
        />

现在在活动文件中添加以下内容。

using Android.Support.V4.App;
using MyApplication.Droid.Library;
//global
public ViewPager mPager;
public PageIndicator mIndicator;
//in on create 
 var indicator = FindViewById<CirclePageIndicator>(Resource.Id.indicator);
            mIndicator = indicator;
            indicator.SetViewPager(mPager);
            indicator.SetSnap(true);

我从github解决了这个问题

答案 1 :(得分:0)

看看这个示例项目&#39; Android-ViewPagerIndicator到Xamarin.Android&#39;。您需要包含库,其中有多个实现,以在viewpager上显示指示符。

https://github.com/Cheesebaron/ViewPagerIndicator

答案 2 :(得分:0)

我像iOS的PageControl一样工作。

这样创建自定义类:

using Android.Content;
using Android.Graphics;
using Android.Graphics.Drawables;
using Android.Runtime;
using Android.Util;
using Android.Widget;
using System;
using System.Collections.Generic;

namespace myProject.CustomWidgets
{
    public class PageControl : LinearLayout
    {
        #region Properties

        private int _currentPage = 0;

        public int CurrentPage
        {
            get
            {
                return _currentPage;
            }

            set
            {
                _currentPage = value;

                SetCurrentPageIndicator();
            }
        }

        public int Pages = 0;

        public Color PageIndicatorTintColor = ColorHelper.Clear;

        public Color CurrentPageIndicatorTintColor = ColorHelper.Clear;

        private readonly Context context;

        private List<ImageView> ivList = new List<ImageView>();

        private List<Drawable> drawableList = new List<Drawable>();

        private readonly int circleSize = 7;

        #endregion Properties

        #region Constructor

        protected PageControl(IntPtr javaReference, JniHandleOwnership transfer) : base(javaReference, transfer)
        {
        }

        public PageControl(Context context) : base(context)
        {
            this.context = context;
            InitConfig();
        }

        public PageControl(Context context, IAttributeSet attrs) : base(context, attrs)
        {
            this.context = context;
            InitConfig();
        }

        public PageControl(Context context, IAttributeSet attrs, int defStyleAttr) : base(context, attrs, defStyleAttr)
        {
            this.context = context;
            InitConfig();
        }

        public PageControl(Context context, IAttributeSet attrs, int defStyleAttr, int defStyleRes) : base(context, attrs, defStyleAttr, defStyleRes)
        {
            this.context = context;
            InitConfig();
        }

        #endregion Constructor

        #region Methods

        private void InitConfig()
        {
            Orientation = Orientation.Horizontal;
        }

        protected override void OnAttachedToWindow()
        {
            base.OnAttachedToWindow();

            Render();
        }

        private void Render()
        {
            // Start with a clean slate
            RemoveAllViews();
            ivList = new List<ImageView>();
            drawableList = new List<Drawable>();

            if (Pages <= 0)
            {
                return;
            }

            for (int i = 0; i < Pages; i++)
            {
                var iv = new ImageView(context);

                var size = ConvertionHelper.DensityToPixels(context, circleSize);
                var margin = (int)(size / 2.5);

                var lp = new LayoutParams(size, size);
                lp.SetMargins(margin, 0, margin, 0);

                iv.LayoutParameters = lp;

                /* By default, all drawables instances loaded from the same resource share a common state.
                 * If you modify the state of one instance, all the other instances will receive the same modification.
                 * Calling this method on a mutable Drawable will have no effect */
                var drawable = ResourcesHelper.GetDrawable(context, Resource.Drawable.ic_circle_separator).Mutate();
                drawable.SetColorFilter(PageIndicatorTintColor, PorterDuff.Mode.SrcAtop);

                iv.SetImageDrawable(drawable);

                drawableList.Add(drawable);

                ivList.Add(iv);

                AddView(iv);
            }

            // Initial current page indicator set-up
            SetCurrentPageIndicator();
        }

        private void SetCurrentPageIndicator()
        {
            if (ivList.Count == 0 || drawableList.Count == 0 || ivList.Count != drawableList.Count ||
                CurrentPage < 0 || CurrentPage >= ivList.Count)
            {
                return;
            }

            // Reset all colors
            for (int i = 0; i < ivList.Count; i++)
            {
                drawableList[i].SetColorFilter(PageIndicatorTintColor, PorterDuff.Mode.SrcIn);
                ivList[i].SetImageDrawable(drawableList[i]);
            }

            // Change color of current page indicator
            drawableList[CurrentPage].SetColorFilter(CurrentPageIndicatorTintColor, PorterDuff.Mode.SrcIn);
            ivList[CurrentPage].SetImageDrawable(drawableList[CurrentPage]);
        }

        #endregion Methods
    }
}

然后在您的xml文件中使用,例如:

<myProject.PageControl
        android:id="@+id/pagecontrol"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"/>

然后在您的活动中,您将拥有:

var pagecontrol = FindViewById<PageControl>(Resource.Id.pagecontrol);
pagecontrol.PageIndicatorTintColor = ColorHelper.PositiveBlue;
pagecontrol.CurrentPageIndicatorTintColor = ColorHelper.Orange;
pagecontrol.CurrentPage = 0;
pagecontrol.Pages = 3;