Matt Coneybeare

MC

How to Best Resize SMPageControl Indicators to Fit Bounds

| Comments

I have been working on a new feature for my Hourly News iOS App that allows the addition of custom news sources to the app. While testing out what happens when a customer adds dozens of feeds, I noticed a problem with UIPageControl

UIPageControl

… it doesn’t resize itself to fit within it’s bounds, and it draws outside of them! So, I started shopping around for an open-source replacement, landing on SMPageControl for it’s customization level, it’s stability and it’s longevity. Swapping the UIPageControl for the SMPageControl was pretty straightforward, and it solved the problem of drawing outside of it’s bounds easily enough.

SMPageControl1

However, when there were more pages than room to fit them, the leading and trailing pages were cut off from the view. Because SMPageControl allows for the customization of the indicator size and margin between them, I wrote a little function that adjusted these values to ensure that all pages will fit and be displayed, within reason.

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
#define PAGE_CONTROL_DEFAULT_PAGE_DIAMETER  8.0
#define PAGE_CONTROL_DEFAULT_PAGE_MARGIN    10.0
#define PAGE_CONTROL_MINIMUM_PAGE_DIAMETER  3.0
#define PAGE_CONTROL_MINIMUM_PAGE_MARGIN    5.0

- (void)sizePageControlIndicatorsToFit {
	// reset defaults
	[self.pageControl setIndicatorDiameter:PAGE_CONTROL_DEFAULT_PAGE_DIAMETER];
	[self.pageControl setIndicatorMargin:PAGE_CONTROL_DEFAULT_PAGE_MARGIN];

	NSInteger indicatorMargin = self.pageControl.indicatorMargin;
	NSInteger indicatorDiameter = self.pageControl.indicatorDiameter;

	CGFloat minIndicatorDiameter = PAGE_CONTROL_MINIMUM_PAGE_DIAMETER;
	CGFloat minIndicatorMargin = PAGE_CONTROL_MINIMUM_PAGE_MARGIN;

	NSInteger pages = self.pageControl.numberOfPages;
	CGFloat actualWidth = [self.pageControl sizeForNumberOfPages:pages].width;

	BOOL toggle = YES;
	while (actualWidth > CGRectGetWidth(self.pageControl.bounds) && (indicatorMargin > minIndicatorMargin || indicatorDiameter > minIndicatorDiameter)) {
		if (toggle) {
			if (indicatorMargin > minIndicatorMargin) {
				self.pageControl.indicatorMargin = --indicatorMargin;
			}
		} else {
			if (indicatorDiameter > minIndicatorDiameter) {
				self.pageControl.indicatorDiameter = --indicatorDiameter;
			}
		}
		toggle = !toggle;
		actualWidth = [self.pageControl sizeForNumberOfPages:pages].width;
	}

	if (actualWidth > CGRectGetWidth(self.pageControl.bounds)) {
		NSLog(@"Too many pages! Already at minimum margin (%d) and diameter (%d).", indicatorMargin, indicatorDiameter);
	}
}

Basically, it checks the calculated full width of the page control, and while that width is wider than the page control’s bounds, alternate a reduction of the indicator margin and diameter until it fits, or until it hits a reasonable minimum size. I call this in viewDidLoad, willAnimateRotationToInterfaceOrientation and also whenever a source is added or removed from the app. Looks much better!

SMPageControl2

Lastly, I run a small software company called Urban Apps. It pays the bills so I can take the time to write helpful posts like this one. If you found this posting helpful at all, I would really appreciate it if you would check out my Apps on the iTunes App Store.

Comments

My name is Matt Coneybeare, I design and develop for iOS (iPhone, iPad and iPod Touch), Mac OS X and the Web out of New York. In 2008 I started a software company called Urban Apps that has made some pretty popular apps such as Ambiance and Hourly News. My current Stack Overflow reputation is about 27k.

I was a Rockstar a decade ago, but then went back to school and collected a Bachelor's Degree in Computer Science from U.C. Berkeley. Now I am settled down with my beautiful wife Di and our two doggies Hamachi and Foxy. While coding, I walk several miles/day on my Treadmill Desk. When not at my desk, I love exploring New York City as a Yelp Elite, or training for marathons.

Contact information

Name
Matt Coneybeare
Email
Website
Twitter
Instagram
GitHub
Google+
LinkedIn