Thanks to Mattt Thompson’s great NSHipster blog, a lot of folks are now “hip” to some pretty obscure stuff in Cocoa and Objective-C. It’s a great blog. Go read it.
It’s not always completely obvious how to use the new tools he highlights though. I found myself reading his article on CGGeometry, utterly surprised by the existence of all those useful convenience functions. But if you’re already sticking numbers into CGRectMake
(as I have been doing for forever), then why would you need functions like CGRectOffset
, CGRectInset
, and CGRectDivide
?
Simple. Don’t use CGRectMake
. Instead, keep track of a working rectangle.
For example, let’s say you’re trying to lay out a tableview cell.
- (void) layoutSubviews {
[super layoutSubviews];
CGRect workingRect = self.contentView.bounds;
This workingRect
variable is your home base. It represents the part of your view that hasn’t been sliced up yet. Let’s say you want to pad everything by a few pixels.
workingRect = CGRectInset(workingRect, 2, 2);
Bam. Done. You want to lay out your imageView
, textLabel
, and detailTextLabel
, so set up some variables.
CGRect imageRect = CGRectZero, textRect = CGRectZero, detailTextRect = CGRectZero;
Okay, time to use the coolest of the tools. CGRectDivide
takes a rect, an amount, and an edge, and “returns” a slice and a remainder.
CGRectDivide (CGRect rect, CGRect *slice, CGRect *remainder, CGFloat amount, CGRectEdge edge);
Let’s assume you’re lazily loading your subviews, so check if you’ve got an image and divide your workingRect
up. The crucial thing here is to pass your workingRect
for your remainder
, so that you can keep working with it. Cut off a square from the left side with a square for the imageView
.
if (_imageView.image) {
CGRectDivide(workingRect, &imageRect, &workingRect, workingRect.size.height, CGRectMinXEdge);
}
Boom. You have an imageRect
now, and you can continue to work with your workingRect
. Do the same with your detailTextLabel
.
if (_detailTextLabel.text.length) {
CGRectDivide(workingRect, &detailTextRect, &workingRect, workingRect.size.height/2, CGRectMaxYEdge);
}
The leftover, whatever it is, is the textRect
.
textRect = workingRect;
Now you can just set your rects to the frames of your objects!
self.imageView.frame = imageRect;
self.textLabel.frame = textRect;
self.detailTextLabel.frame = detailTextRect;
}
You’re done. Easy like Sunday morning, and a lot more readable than a half dozen CGRectMake
calls.
In the last post, I discussed how to make a paging scroll view with hints on either side. This is a pretty common effect to try to achieve, and it’s nice to know that it can be done without too much effort now.
Of course, the natural progression of having many pages of views in a scrollview is to manage them with a UICollectionView
. This complicates matters for us a lot, however. The collection view knows where all its cells are (no matter what layout you give it), so it automatically removes cells that are outside its visible bounds, the same way a tableview does. This breaks our clipsToBounds
trick, because as soon as they move outside the bounds, they disappear.
But we are smarter than UICollectionView
, and we will prevail.
Technique
Below is the simplest way to get the job done. It involves a collection view and an extra secret scroll view.
Set up your collection view
Set up your collection view and all its data source methods.
Frame the collection view; it should span the full width that you want to be visible.
Set the collection view’s
contentInset
:_collectionView.contentInset = UIEdgeInsetsMake(0, (self.view.frame.size.width-pageSize)/2, 0, (self.view.frame.size.width-pageSize)/2);
This helps offset the cells properly.
Set up your secret scrollview
Create a scrollview, place it wherever you like. You can set it to
hidden
if you like. TurnpagingEnabled
on.Set the size of the scrollview’s bounds to the desired size of your page.
Set yourself as the delegate of the scrollview.
Set its
contentSize
to the expected content size of your collection view.
Move your gesture recognizer
Add the secret scrollview’s gesture recognizer to the collection view, and disable the collection view’s gesture recognizer:
_collectionView addGestureRecognizer:_secretScrollView.panGestureRecognizer]; _collectionView.panGestureRecognizer.enabled = NO;
Delegate
- (void) scrollViewDidScroll:(UIScrollView *)scrollView {
if (scrollView == _secretScrollView) { //ignore collection view scrolling callbacks
CGPoint contentOffset = scrollView.contentOffset;
contentOffset.x = contentOffset.x - _collectionView.contentInset.left;
_collectionView.contentOffset = contentOffset;
}
}
As the scrollview moves, get its offset and set it to the offset of the collection view.
And you’re done! It’s a little less elegant than the previous solution, but this is the price we pay to get to use UICollectionView
.
For extra credit: create a new UICollectionLayout
subclass that overlaps the cells slightly and invisibly so that the collection view can’t remove those cells. (ed. I think this is impossible.)
There aren’t really any good names for this effect, but at some point every app developer wants to make it. You can see it in Safari on iOS, when you zoom out to the tab switcher. You can swipe between the pages, and it’s clearly a paging scroll view, but it becomes more complicated because of the hints of the next and previous pages.
A paging scrollview’s page size is the size of the scrollview’s bounds, with no way to adjust it. If you want to show hints of the next and previous “pages”, you have to make the scrollview’s width the width of the page you’d like and set clipsToBounds
to NO
. Then, the scrollview looks the way you expect, but the areas outside the scrollviews bounds are not user-interactable, so your app feels broken. There are pages begging to be touched on the left and right, but the user can’t move them.
A lot of the things I blog about are not necessarily about how to do something that’s never been done before, but rather better ways to do things we can do already. In other words, there’s an old and busted way to do this, and there’s the new hotness.
The old way
The old way, thoroughly documented since 2009 on Stack Overflow and elsewhere, is to:
turn off
clipsToBounds
on your scroll view,make size of the scroll view the intended size of your pages,
make a custom UIView subclass,
place the view over the area that you’d like to user to be able to touch to begin their scrolling events
override the
– hitTest:withEvent:
function like so- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { if ([self pointInside:point withEvent:event]) { return _scrollView; } return nil; }
The better way
This all changes in iOS 5.0, when Apple exposed the panGestureRecognizer
property on UIScrollView
. Suddenly, our life got a lot easier. Now, all we have to do is:
turn off
clipsToBounds
put a
UIView
over the scrollview, wherever you want the user to be able to touchmove the
panGestureRecognizer
to that view[touchableView addGestureRecognizer:_scrollView.panGestureRecognizer];
Done!
This seems like it might be a hack that Apple could break at any time, but it’s actually Apple-sanctioned. (cf WWDC Session 223, “Enhancing User Experience with Scroll Views”. The second time they gave that talk, they specifically mentioned that UIScrollView's
panGestureRecognizer
and pinchGestureRecognizer
were designed with the expectation that they could be moved.)
This seems like it is a pretty trivial new technique, but as we’ll see in the next blog post, it’s actually crucial for use with more modern technologies.
Update: @autresphere on Twitter has pointed out to me that you can set the animation duration to 0 and no animation will occur. This works and is more effective than the block-based method below. I also did a little further testing, and the animations
block is performed synchronously, but the completion
block is not. They are both performed on the main thread, of course. I’ve updated the GitHub repository with this new code.
Original Post:
I’ve been working a lot recently with Container View Controllers, and in a lot cases, you want to provide an API for choosing whether the transition should be animated or not. This is useful if the user of the API wants to rebuild the navigation controller stack on first launch. In SKNavigationController
, I was doing these as separate blocks in an if/else construct, and repeating code.
- (void) pushViewController:(UIViewController *)viewController animated:(BOOL)animated {
newViewController.view.frame = //original frame
[self addChildViewController:newViewController];
if (!animated) {
[self.view addSubview:newViewController.view];
[oldViewController.view removeFromSuperview];
newViewController.view.frame = //new frame
[newViewController didMoveToParentViewController:self];
} else {
[self transitionFromViewController:oldViewController
toViewController:newViewController
duration:0.35f
options:0
animations:^{
newViewController.view.frame = //new frame
}
completion:^(BOOL finished) {
[newViewController didMoveToParentViewController:self];
}];
}
}
We’re trying not to repeat ourselves, and we already have these handy blocks that describe the state after our animation is complete ( animations
) and what to do when the animation is complete ( completion
). Let’s just turn these into standalone blocks, and call them right on the main thread if the pushing is not animated
.
- (void) pushViewController:(UIViewController *)viewController animated:(BOOL)animated {
newViewController.view.frame = //original frame
[self addChildViewController:newViewController];
void (^animations)(void) = ^{
newViewController.view.frame = //new frame
};
void (^completion)(BOOL finished) = ^(BOOL finished){
[newViewController didMoveToParentViewController:self];
};
if (!animated) {
[self.view addSubview:newViewController.view];
[oldViewController.view removeFromSuperview];
animations();
completion(YES);
} else {
[self transitionFromViewController:oldViewController
toViewController:newViewController
duration:0.35f
options:0
animations:animations
completion:completion];
}
}
A little weirder looking if you like Objective-C syntax and get freaked out by the carets (^) in the block syntax, but much cleaner and easier to maintain.
I’ve updated the SKNavigationController
GitHub repository to reflect this.
View Controller containment is a set of UIViewController
APIs that were introduced with iOS 5. I didn’t know much about it, or even really what the purpose of such a thing was. I’ve written a few container view controllers, mostly custom tab bar controllers, by using what I would call the “old and busted” way:
[selectedViewController viewWillDisappear:NO];
selectedViewController.view.hidden = YES;
[selectedViewController viewDidDisappear:NO];
vc = viewControllers[index];
selectedViewController = vc;
vc.view.frame = self.view.bounds;
[self.view addSubview:vc.view];
[vc viewWillAppear:NO];
vc.view.hidden = NO;
[vc viewDidAppear:NO];
This works, but it’s unreliable. I’m manually calling the appearance methods, but will rotation methods be called on every sub-viewcontroller? Memory warnings? What is the value of parentViewController
?
What do we get?
Forwarded methods
It turns out, using container view controllers cleans all that up for you, at a small upfront cost. The main purpose of it is to forward methods:
Appearance methods:
-viewWillAppear
and friendsRotation methods:
-willRotateToInterfaceOrientation
, etcThe memory warning method:
-didReceiveMemoryWarning
These methods are forwarded by default, and can be modified in iOS 5 and above with:
- (BOOL) automaticallyForwardAppearanceAndRotationMethodsToChildViewControllers
and iOS 6 and above with:
- (BOOL) shouldAutomaticallyForwardRotationMethods
- (BOOL) shouldAutomaticallyForwardAppearanceMethods
Properties
View controller containment also helps set properties like navigationController
, parentViewController
, and interfaceOrientation
correctly.
New stuff
We also get a few things we couldn’t really get before, also for free:
– isMovingFromParentViewController;
– isMovingToParentViewController;
- isBeingPresented;
– isBeingDismissed;
These faux-properties can be called during transitions, and give your app a better sense of its state.
So what is view controller containment?
View controller containment is simply a way of telling your parent and child view controllers which is which. They give us some methods, which are unfortunately very unclear and don’t tell us which are required and which are not.
- addChildViewController:
- removeFromParentViewController
- willMoveToParentViewController:
- didMoveToParentViewController:
-transitionFromViewController:toViewController:duration:options:animations:completion:
So, to explore containment, I wrote two small replacements for the UIKit
view controller containers, SKTabBarController
, and SKNavigationController
.
Both examples are in ARC.
SKTabBarController
SKTabBarController can be found at github.com/khanlou/SKTabBarController.
The tab bar controller is very simple.
It has a tab bar, and it registers as the delegate of that tab bar.
The
viewControllers
property can be set, and that adds all of the view controllers as child view controllers.When a tab bar button is tapped, the delegate method is called, and
If the already-selected button is being tapped, it pops to the root of that navigation controller.
If a different button is being pressed, it removes the old view, sets the frame, and adds the new view.
Child View Controllers
The addChildViewController:
and removeFromParentViewController
can be thought of as view controller counterparts to addSubview:
and removeFromSuperview
. They’re asymmetric, meaning that one is called on the parent (“add”) and one is called on the child (“remove”). The view controller methods add view controllers to the childViewControllers
property, in the same way that the view methods add to the subviews
property.
The view controller methods MUST be called before the view methods.
Once a child is a member of parent view controller, simply calling addSubview:
or removeFromSuperview
will automatically call the appropriate appearance methods.
Child Callbacks
When calling addChildViewController:
and removeFromParentViewController
, you must let the view controller know that you are about to move it, and that’s where these methods come in:
willMoveToParentViewController:
didMoveToParentViewController:
When adding a child view controller,willMoveToParentViewController:
is automatically called, butdidMoveToParentViewController:
is not, and you must manually call it.
The reverse is the case for removing a child view controller. willMoveToParentViewController:
should be passed nil
, but didMoveToParentViewController:
will be called for you.
Proper Use Of childViewControllers
Originally, I had this container class adding children only when the button was tapped and removing them when a different button was tapped, but that feels wrong. A child is still a child, even if it’s not visible. You can browse the incorrect code at commit 297c2dc7a2. The current code is updated, and adds child view controllers when the viewControllers
property is set.
SKNavigationController
SKTabBarController can be found at github.com/khanlou/SKNavigationController.
I didn’t use any animations in SKTabBarController
, so things got more interesting when I tried to make a navigation controller.
The navigation controller still pretty straightforward.
It has a navigation bar, and it registers as the delegate of that navigation bar.
The
viewControllers
property can be set, and that adds all of the view controllers as child view controllers, and pushes their navigation items onto the navigation bar.The push and pop methods of the navigation controller use
-transitionFromViewController:toViewController:duration:options:animations:completion:
for animations.
Pushing a New View Controller
When pushing a new view controller, we must do several things.
Add it to the parent view controller.
Create a navigation item for it, and add that item to the navigation bar.
If animated, we need to set up a transition.
At the end of the animation, we need to tell the pushed view controller that it has been fully moved to the parent.
Transitions are weird. They’re like traditional UIView
animations, but they do more things for you.
[self transitionFromViewController:oldViewController
toViewController:newViewController
duration:0.35f
options:0
animations:^{
newViewController.view.center = oldViewController.view.center;
oldViewController.view.center = CGPointMake(oldViewController.view.center.x - self.view.bounds.size.width, oldViewController.view.center.y);
}
completion:^(BOOL finished) {
[newViewController didMoveToParentViewController:self];
}
];
Let’s go through it step-by-step.
fromViewController
andtoViewController
must exist, and have the same parent.options
can include anyUIView
animation options, including several of the built in animation transitions.animations
can be used for custom animations.completion
is used to call anydidMoveToParentViewController:
callback methods, and cleanup for your animation.
Adding and Removing the Subview
transitionFromViewController:
automatically calls addSubview:
with toViewController.view
. Calling it yourself will result in the incredibly frustrating >
Unbalanced calls to begin/end appearance transitions for
It will also automatically call removeFromSuperview
on fromViewController.view
.
Popping an View Controller off the Stack
Popping is very similar to pushing.
Tell the view controller coming off the stack that it is being moved to a
nil
parent.Pop the navigation item off the navigation bar.
Set up the transition.
Upon completion, fully remove the popped navigation controller from the parent.
I won’t include the code for the sake of brevity.
Takeaways
There are three takeaways:
Adding a child view controller must be followed by
didMoveToParentViewController:self
.Removing a child view controller must be preceded by
willMoveToParentViewController:nil
.Transitions automatically handle adding and removing of the child view controllers’ views.
This is the third part in a 3-part series on fixing the electoral system in America. Part one discusses the problems that our voting system creates, and the second post proposes solutions for voting for a candidate in a single office.
In the first post, I touched on the problem of gerrymandering. Gerrymandering is changing the borders of a voting district so that the voting power of the people in that district is increased or decreased.
Gerrymandering is rampant in America because the people who will be elected in a district are the ones who get to draw the boundaries. They can draw borders that will safely vote them in whenever an election comes around. If there’s a group of like-minded (like-partied?) members in an area, they can work together to divide voters who would vote for any other party into several of their own districts, which would blunt the effect of those voters. This is a form of voter suppression, and our voting system should do everything in its power to limit this.
By redistricting, we can create a wide array of outcomes
There are a few things we can do to reduce the effects of gerrymandering. We can use an independent commission to draw the boundaries, and this can help a little bit. They might still be partisan or susceptible to bribes, so this can be dangerous.
We can also use a computer algorithm to calculate the district boundaries. The simplest algorithm that is regarded as fair is the shortest split-line method. Simply put, it finds the shortest line that splits the population of an area in two and then repeats that process with the two smaller areas until districts are created with the desired number of voters in each. However, it can split cities and neighborhoods. Since communities like that are logical voting groups with common interests, we want them to be represented together.
Fortunately, we can change our voting system to reduce the effect of gerrymandering.
First Past The Post
FPTP for a body of elected officials is the same as for a single election, just on a smaller scale. This is what we have in America. The country is divided into states, which are subdivided into districts. Each district gets one representative, and he or she is elected by a FPTP system, where each voter gets exactly one vote. We have the same problems here as with the single election FPTP system.
Multiple-Winner Proportional
What if we got rid of districts altogether? This would solve the problems of gerrymandering. Each person votes for a party instead of a candidate, and each party gets a number of seats according to what percentage of the vote it received. The party decides who will fill those seats ahead of time by publishing an ordered list. This is called a multiple-winner proportional system.
We don’t have to worry about about districts that are cut up to discount people, which is great, but we lose the ability to have a representative that is directly answerable to a person in a district. If your roads are messed up, who do you call? None of the representatives you voted for are necessarily from your community, and they don’t know about the specific problems that you and your neighbors face.
A lot of parliamentarian systems are based on this pattern. You can find it in action in countries like Germany and England. If we switched to multiple-winner proportional elections in America, voters would never be punished for straying outside the two political parties, and more parties would survive. Since none of them would have a majority, they have to work together to pass bills on issues.
Mixed-Member Proportional
So we know we want districts, but we also want a way for people who have been excluded because of gerrymandering to have a voice. We need to mash these two systems up to get the best of both worlds.
The way to do that is to give everyone two votes. One vote for a representative for their district, and one vote for a party.
We take the first vote, and use it to find representatives for each district. These districts are drawn by commissions that are as independent as possible. They can be elected using any of of the ranked, approval, or even FPTP systems that I discussed in the last post. These representatives fill 50% of the seats in the chamber.
For the other 50% of the chamber, we use the second vote to give seats to the party in such a way that the final distribution of all of the seats in the chamber matches the distribution of all the party votes in the country.
For example, imagine two parties in a country, Party A and Party B. They have roughly the same number of supporters each. Even if Party A had managed to win most of the representative seats through gerrymandering, most of the remaining seats would be given to Party B, so that the total distribution is about half and half. This way nobody can be silenced through gerrymandering, but we also get the benefit of having local representatives.
This is the gold standard of representative election. New Zealand has started using this system, and they call it mixed-member proportional. The ratios of the seats don’t have to be 50% representative seats and 50% party seats, they can be adjusted for the exact effect a country needs.
Sources
I couldn’t have written this post without the excellent YouTubes that CGP Grey has made. You can see all the ones about politics here. I highly recommend watching all of them, because they’re well made, and they visually explain a lot of the concepts I’ve discussed, with cute animals to boot.
I also drew a lot of inspiration from the Ka-Ping Yee’s voting simulation that I linked to earlier. This is also very much recommended.
Thanks for reading. If you missed them, definitely check out the first and second posts in the series, which discuss what the problems are, and how to fix them for a single office.
This is part two in a 3-part series about how to change our electoral system for the better. The first post discusses the problems that our voting system creates, and the third post talks about what we can do about gerrymandering.
In the previous post, I laid out three really big problems with our current electoral system:
It makes some people quiet and some people loud through the electoral college.
It encourages gerrymandering by giving the wrong people the wrong incentives.
Over time, it results in two parties.
To solve the Electoral College problem, we should just get rid of it. I’ll address how to fix gerrymandering and redistricting in the next post. In this post, primarily, I’m going to address the third problem, where we end up with two parties over time. The two party problem is the direct result of voters getting exactly one vote. Having one vote is, of course, better than having no votes, but it could also be much, much better.
Well then, how many votes should people get?
We can give them as many votes as we want: one, or two, or as many as they want, or infinite. Each of these changes has drastic effects on the voting system, and some of them are very desirable.
I’m going to run through a few voting systems that can help us elect a person for one office, such as the President of the United States (topical!) in this post, and in the next post, I will discuss how we can make a body of representatives in a legislature be more fairly elected.
First Past The Post
First Past The Post is the system that we have now. The first candidate to reach 50%, or simply the one that gets the most votes, wins. This is the most obvious choice, but it can also have some unintended consequences.
If you give everyone one vote, then the only reliable metric you can judge is a voter’s first choice. Since the voter’s choice is an incredibly rare resource, they’re going to use it as carefully as possible. This means they’ll be afraid to use it in an experimental capacity (like voting for a third party candidate, or a candidate that is clearly not going to win), deciding instead probably to just stay at home.
In this system, voters tend to use their vote to prevent one candidate from winning, rather than to try to get a particular candidate elected. For example, a libertarian in America might want Ron Paul to win the election, fearing that Romney isn’t fiscally conservative enough, but they would probably still vote for Romney, to make sure that Obama doesn’t win.
This is how you end up with two parties. Even if you start with a large number of parties, only a few are going to stand out in that crowd. As elections continue, people will abandon their smaller parties and join the bigger ones until there are only two left and they can not further consolidate. Historically, FPTP gives us two very narrow parties, with no clear way for third parties to break in.
FPTP can also be especially harmful in smaller elections, like local ones. If there are three candidates, there is a scenario in which the winning candidate got 34% of the vote, and the two losers got 33% each. This means that a healthy majority (66%) didn’t want the candidate that actually won the election.
Approval
If you give voters as many votes as they want, you have an approval system. With an approval system, as a voter, you would just check off every candidate on the ballot that you agree with. You wouldn’t be able to vote for one candidate more than once, but you could vote for all but one, for example.
Approval solves several problems. First, voters can support a third party without fear that it will cause someone they don’t like to be elected. To use the resource analogy from earlier, the approval system removes the scarcity of votes, which both allows people to be more experimental, and lets them be more honest about which candidates they want in office, without any external pressure.
This method of voting mostly provides information about how popular parties would be, and it lets the state to allocate funds accordingly. In America, 5% popular vote is a crucial number for a party to hit: it makes them eligible for matching funds. It would be way easier to hit this number if voters didn’t have to worry that the other acceptable party might lose to the unacceptable party as a result of their actions. And of course, over several voting cycles, approval voting allows a third party to gain attention without a voter ever having to stop supporting one of the major parties.
The last benefit to an approval system is that you never need to wonder how much of the population disapproves of one of the candidates, like they might in our local election example above. If none of the candidates can even convince 50% of the people in a population that they are worthy, you know that you have a very big problem.
Ranked Voting Systems
The final way to usefully elect a single candidate is to rank them. Ranks have to be in sequential order, two candidates can get the same rank, and not all candidates have to be ranked.
This voting system gives us flexibility. Once we have all of this information about the voters’ preferences, we can use a few different things to actually select a winner. The most simple thing we can do is tally up all the votes, and have the candidate with the lowest rank elected.
We can get weird, and use a Condorcet system: in this system, the winner is the candidate that defeats all of the other candidates in one-on-one comparisons. Condorcet is a particularly interesting and strange voting system because we can end up with a rock-paper-scissors situation, where Candidate A beats Candidate B, Candidate B beats Candidate C, and Candidate C beats Candidate A. Since it can be broken in this really simple way and understanding it is a little more difficult than other systems, it’s not really an ideal solution. It does have the huge benefit that if there is a Condorcet winner, you at least know that voters would choose them in every possible scenario (one-on-one with any other candidate).
Lastly, we can do instant runoffs: since we know which candidates the voters would have elected for if their top choice wasn’t available, we have enough information to determine who would win if a given person was taken out. If no candidate has more than 50% of the vote, we can take out the worst-ranked candidate until we have one that has a simple majority. A lot of local elections in America do run-offs a month after the November election because they don’t have a clear winner. This would completely eliminate such situations, and save everyone a little time and money.
Simulations
We can also simulate how people would act in certain situations, and we can see what effects these policies have on voters. Ka-Ping Yee did a series of simulations on his site, zesty.ca, and the results are interesting. I encourage you to read it all, but I’ll include one example below.
We can see that in a First Past the Post system, nobody votes for the third party when another person is clearly going to win. As you change the systems, though, that voters for the third party increase. Also, interestingly, having a third party on your side of the map can actually cause your opponent to lose, which makes sense. More people are likely to agree with you and the third party on your side than those that disagree.
Let’s vote
My personal favorite of all of these methods is the approval system. It’s simple, clear, easy to understand, and helps people voice their opinions about third parties. The only way to get more people to vote in this country is to give them better ways to be heard.
Be sure to check out parts two and three of this series. The first post discusses the problems that our voting system creates, and the third post talks about how to elect candidates for a chamber full of representatives, like a legislature.
This is the first in a three-part series on voting and voting systems, and how to empower the citizens of a nation. This post discusses the problems we have. The second post covers how to improve elections of a single office, and the third post talks about gerrymandering and how we can avoid it.
I’ve become more and more obsessed with electoral systems recently. Winston Churchill once said, “Democracy is the worst form of government, except all the others that have been tried”, and that seems to ring true in a lot of ways. We can imagine lots of governments that are worse than democracy, but even our own democracy makes us feel like we aren’t being heard or represented. That’s not by accident.
They Say College Is Good For You
The Electoral College is the body that elects the President. it consists of 538 members, and each member corresponds to either a district or a state of the United States. The District of Columbia also gets three votes (as if it had a Representative and two Senators, like all the other states).
The Electoral College exists because some of the Founding Fathers thought that a nation of farmers couldn’t be trusted to elect a new set of governmental representatives every few years. They created the Electoral College to dampen the effect of individual voters. Votes in the college are awarded on a per-state basis, so a state could be barely won, or it could be won in a landslide, and it would make no difference: the candidate for president still gets the votes for that state.
The Electoral College, of course, is why we can have a candidate for president win the “popular” election, which is named in a way that might make you think it’s a popularity contest, and another candidate win the “real” election.
It’s also why we can have a situation like this:
From fivethirtyeight.blogs.nytimes.com, pulled October 20, 2012
Even though I’d rather Obama win than Romney, a situation like this is appalling and should never happen. For Obama to have a 67% chance of winning even though he only has just barely enough of the popular vote is a testament to how much the Electoral College dampens the effects of the voters.
Further, the free vote each state gets (for its Senator) amplifies the voice of people in small states over those in large states. Roughly every 670,000 people in Texas gets an electoral vote, whereas 330,000 Montana citizens get an electoral vote.
Your Old Friend Gerald
When discussing districts and the problems with the electoral system, we can’t ignore gerrymandering. Gerrymandering is drawing the borders of a district to increase or decrease the voting power of certain people in that district. A great example is Austin, where the citizens are squeezed out of having their own representative. The city is split into thirds, and each part of the city is grouped with large swaths of the conservative Texas countryside.
The primary problem is that the districts are drawn by the very representatives that will be elected in them, and this leads to two things. First, minorities in a region will get grouped with majorities in such a way that they can’t win districts, and second, the representatives have huge incentive to draw boundaries that are very safe for them to get elected in.
We could get rid of districts entirely, but they are useful. They provide an accountable person in office, who (ideally) comes from the same area as their electorate, and can speak for its residents in the legislature. Districts should be built around communities, with similar interests. There should also probably be a lot more representatives. Smaller voting bodies means the interests of the represented are more aligned.
The 4th District of Illinois
Smaller districts would also help in other ways. This clearly gerrymandered district in Chicago was carved out so that the Puerto Ricans in the north and Mexicans in the south can have a representative in Congress, and with more representatives, it might look like two very normal looking districts.
The Elephant and the Donkey
Americans also feel frustrated specifically by the two-party system, and it’s clear that it doesn’t satisfy us.
We saw this in the 2000s pretty readily. In 2006, The Zeitgeist was frustrated with George Bush, and voted a lot of Democrats into the House. In 2008, of course, they also elected Barack Obama. Nobody was happy, as you might expect, since most people don’t actually fall in line that well with our two given parties. The Republicans appealed to that dissatisfaction and won a ton of seats back in the House and the Senate in 2010. And so it goes, with neither side really satisfying the voter base, because the ideologies of the parties are too tight to appeal to such a wide group of people. This probably helps to explain why only 40% of Americans vote.
If you consider yourself a political extreme, you can’t even deviate from the parties, in fear that you’d be “throwing your vote away”, and causing the party you dislike to win the election. No Democrat can forget 2000, where Nader took 100,000 votes in Florida which would have tipped the scales for Gore. Even just New Hampshire, which was also taken by Bush with a smaller margin than Nader’s votes, would have been enough to give the election to Gore.
Inevitability
It turns out that a two-party system (and the other problems I’ve mentioned here) is inevitable because of the way our voting system is designed. We need ways to get more information about voter’s preferences and find a way to empower more voters.
Be sure to check out parts two and three of this series. They describe how we can work to fix these problems.
FTWButton
is a UIControl
subclass that lets you easily set color, gradient, text, shadow, border, and icon properties for various states and animates between them.
You can find it at FTW’s GitHub, at github.com/FTW/FTWButton
Usage
Using FTWButton
is similar to UIButton
, but it’s built from the ground-up. Instead of relying on background images, FTWButton
draws itself.
Properties
FTWButton has several properties, that can be set for each state:
Frame
Background Color
Background Gradient Colors
Corner Radius
Icon
Text
Text Color
Text Shadow Color
Text Shadow Offset
Border Color
Border Gradient Colors
Border Width
Shadow Color
Shadow Offset
Shadow Opacity
Shadow Blur Radius
Inner Shadow Color
Inner Shadow Offset
Inner Shadow Blur Radius
They are all animatable and transition between states.
Example Code
button1 = [[FTWButton alloc] init];
button1.frame = CGRectMake(20, 20, 280, 40);
[button1 setColors:[NSArray arrayWithObjects:
[UIColor colorWithRed:2.0f/255 green:184.0f/255 blue:255.0f/255 alpha:1.0f],
[UIColor colorWithRed:0.0f/255 green:68.0f/255 blue:255.0f/255 alpha:1.0f],
nil] forControlState:state];
[button1 setInnerShadowColor:[UIColor colorWithRed:108.0f/255 green:221.0f/255 blue:253.0f/255 alpha:1.0f] forControlState:UIControlStateNormal];
[button1 setInnerShadowOffset:CGSizeMake(0, 1) forControlState:UIControlStateNormal];
[button1 setShadowColor:[UIColor blackColor] forControlState:UIControlStateNormal];
[button1 setShadowOffset:CGSizeMake(0, 1) forControlState:UIControlStateNormal];
[button1 setShadowOpacity:1.0f forControlState:UIControlStateNormal];
[button1 setTextColor:[UIColor colorWithWhite:1.0f alpha:1.0f] forControlState:UIControlStateNormal];
[button1 setTextShadowColor:[UIColor colorWithWhite:78.0f/255 alpha:1.0f] forControlState:UIControlStateNormal];
[button1 setTextShadowOffset:CGSizeMake(0, -1) forControlState:UIControlStateNormal];
[button1 setText:@"Tap me" forControlState:UIControlStateNormal];
[button1 setText:@"Tapped!" forControlState:UIControlStateSelected];
[button1 addTarget:self action:@selector(buttonTapped:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:button1];
You can combine this code and other styles in any way you like.
Built-in Styles
This code is a bit verbose, so we’ve included several default styles, with colors chosen by our designer.
These styles are:
A disabled style (gray gradient background, gray text)
A delete style (red)
A gray style
A light blue style
A richer blue style
A yellow style
A black style
Feel free to use the format to add your own. Please note that many of the styles add a highlighted state as well.
With those styles, the code becomes much simpler:
button1 = [[FTWButton alloc] init];
button1.frame = CGRectMake(20, 20, 280, 40);
[button1 addBlueStyleForState:UIControlStateNormal];
[button1 addYellowStyleForState:UIControlStateSelected];
[button1 setText:@"Tap me" forControlState:UIControlStateNormal];
[button1 setText:@"Tapped!" forControlState:UIControlStateSelected];
[button1 addTarget:self action:@selector(buttonTapped:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:button1];
Setting button1.selected
to YES
will change the color to yellow, and fade the text from “Tap me” to “Tapped”.
Bridges the gap between design tools and code tools
There are several things that Photoshop makes easy, such as inner shadows and border gradients, that are fairly difficult to do without images (and in some cases, even with images) in iOS. If you’re building a dynamic button with text and colors, consider making it with FTWButton
, so you can rapidly adjust it to see what it would look like in the app itself.
Also, consider a color framework such as EDColor, which can make adding colors to FTWButton
much easier.
Demo App
The demo app contains several examples of FTWButton
, including changing color on selection, border animations, gradient borders, fancy inner shadow, icons, and changing the frame on selection.
Animations in iOS are easy, except when they’re not. I learned this the hard way making SKBounceAnimation
, when I learned about how explicit animations are so different and weird compared to implicit animations.
Today, I learned a new lesson. You would think something like
mySublayer.cornerRadius = 3;
myView.frame = CGRectMake(0, 0, 100, 100);
[UIView animateWithDuration:0.25 animations:^{
mySublayer.cornerRadius = 5;
myView.frame = CGRectMake(50, 50, 100, 100);
}];
would just work. But apparently you can’t perform sublayer animations in an animateWithDuration:
block, so your CALayer
just picks its own duration and timing function, and animates it anyway. This can be a subtle effect, but if you flip the Toggle Slow Animations
flag in the Simulator, it becomes super obvious, since CATransactions
aren’t affected by that menu item.
The solution is to create a separate CATransaction
mySublayer.cornerRadius = 3;
myView.frame = CGRectMake(0, 0, 100, 100);
CGFloat duration = 0.18f;
[CATransaction begin];
[CATransaction setAnimationDuration:duration];
[CATransaction setAnimationTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut] ];
mySublayer.cornerRadius = 5;
[CATransaction commit];
[UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionAllowUserInteraction|UIViewAnimationCurveEaseInOut animations:^{
myView.frame = CGRectMake(50, 50, 100, 100);
} completion:^(BOOL finished) { }];
Your CATransaction can be inside your animations
block if you like. Apple warns that
This type of mixing should not be used in situations where precise timing is needed.
but it looks pretty dead-on to me. The only information about doing this kind of thing is found in three paragraphs on the Apple documentation site, found here.