sgmunn

Mostly MonoTouch with a chance of Other Stuff.

Subclassing UIPageControl

The indicators of UIPageControl are white and grey, which is great on dark backgrounds but not so good when you have light or white background. You also can’t change much about its appearance which seemed a bit of a bother.

My immediate reaction at this point was to subclass UIPageControl and override Draw(rect) and draw the indicators how I needed them. I searched, found some drawing code already done, and pasted it in. Imagine my surprise when I found that it wasn’t drawing correctly, the inactive page indicators appeared correct and the active page indicator appeared as a dark ring instead of a solid dot.

I discovered, as others have here that UIPageControl doesn’t draw the indicator dots, it uses sub-views to display the indicators. Overriding Draw isn’t going to help you at all - your drawing will be under the default rendering.

The solution is to implement your own UIPageControl derived from UIControl, which I did and will put into a library I’m calling MonoKit. For now the (partial) replacement of UIPageControl is this

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
namespace MonoKit.UI
{
  using System;
  using System.Drawing;
  using MonoTouch.UIKit;

  /// <summary>
  /// Implements a replacement for UIPageControl.
  /// </summary>
  public class PageControl : UIControl
  {
    private int pageCount;
    private int currentPage;
    private bool hidesForSinglePage;
    private UIColor activePageColor;
    private UIColor inactivePageColor;

    /// <summary>
    /// Initializes a new instance of the <see cref="MonoKit.UI.PageControl"/> class.
    /// </summary>
    public PageControl(RectangleF frame) : base(frame)
    {
      this.HidesForSinglePage = false;
      this.BackgroundColor = UIColor.Clear;
      this.Enabled = false;
      this.ActivePageColor = UIColor.DarkGray;
      this.InactivePageColor = UIColor.LightGray;
    }

    /// <summary>
    /// Gets or sets the number of indicators that the page control should display
    /// </summary>
    public int Pages
    {
      get
      {
        return this.pageCount;
      }

      set
      {
        this.pageCount = value;
        this.SetNeedsDisplay();
      }
    }

    /// <summary>
    /// Gets or sets the current page number.
    /// </summary>
    public int CurrentPage
    {
      get
      {
        return this.currentPage;
      }

      set
      {
        this.currentPage = value;
        this.SetNeedsDisplay();
      }
    }

    /// <summary>
    /// Gets or sets a value indicating whether the indicators should be hidden when there is only 1 page
    /// </summary>
    public bool HidesForSinglePage
    {
      get
      {
        return this.hidesForSinglePage;
      }

      set
      {
        this.hidesForSinglePage = value;
        this.SetNeedsDisplay();
      }
    }

    /// <summary>
    /// Gets or sets the color of the active page indicator
    /// </summary>
    public UIColor ActivePageColor
    {
      get
      {
        return this.activePageColor;
      }

      set
      {
        this.activePageColor = value;
        this.SetNeedsDisplay();
      }
    }

    /// <summary>
    /// Gets or sets the color of the inactive page indicators
    /// </summary>
    public UIColor InactivePageColor
    {
      get
      {
        return this.inactivePageColor;
      }

      set
      {
        this.inactivePageColor = value;
        this.SetNeedsDisplay();
       }
    }

    /// <summary>
    /// Draws the page indicators 
    /// </summary>
    public override void Draw(RectangleF rect)
    {
      if (!this.HidesForSinglePage || this.Pages > 1)
      {
        var context = UIGraphics.GetCurrentContext();
        context.SaveState();
        context.SetAllowsAntialiasing(true);

        var dotSize = 5;
        var dotsWidth = (dotSize * this.Pages) + (this.Pages -1) * 10;
        var offset = (this.Frame.Size.Width - dotsWidth) / 2;
        for (int i = 0; i < this.Pages; i++)
        {
          var dotRect = new RectangleF(offset + (dotSize + 10) * i, (this.Frame.Size.Height / 2) - (dotSize / 2), dotSize, dotSize);
          if (i == this.CurrentPage)
          {
            context.SetFillColor(this.ActivePageColor.CGColor);
            context.FillEllipseInRect(dotRect);
          }
          else
          {
            context.SetFillColor(this.InactivePageColor.CGColor);
            context.FillEllipseInRect(dotRect);
          }
        }

        context.RestoreState();
      }
    }
  }
}

Cheers.

Comments