Home » UIGestureRecognizer not working with overlapping views

UIGestureRecognizer not working with overlapping views

Problem

Overlapping views not working

I have a hand of cards that are arranged horizontally and overlapping. The UIGestureRecognizer is not working properly in the areas where the cards intersect/overlap. See the image below:

overlapping view
Overlapping views

Background:

The problem has to do with how the UIViews are placed onto the main view. I was programmatically setting the x, y, and z positions of each one. This should work, but for the order in which they were added to the stage. I created the views using a loop:

Set Up the card views

“Deal” the Cards

Then add them to the stage using a for-in loop:

See the Result

The expected order would be hand[1], then hand[2], hand[3], etc. Like this:

  1. card 1 (whose layout properties would place it at far left)
  2. card 2 (whose layout properties would place it 2nd from left)
  3. card 3 (whose layout properties would place it 3rd from left)
  4. etc…

Cards dealt left-to-right
Expected “dealing” order… left-to-right

But wait! The cards are not “dealt” in the order of hand[1], hand[2]…hand[13]. Instead, they are “dealt” (as near as I can tell) randomly (or at least not in the sequence of their keys). I was getting: hand[5], hand[13], hand[12], etc. To help visualize this, imagine you’re looping through all the “cards” in the “hand”…. Escaping before they were all placed I could see the cards looked like this:

  1. card 5 (whose layout properties would place it fifth from left)
  2. card 13 (whose layout properties would place it 13th from left)
  3. card 12 (whose layout properties would place it 12th from left)
  4. etc

Unexpected (and problematic) "deal" order (random)
Unexpected (and problematic) “deal” order (random)

So the cards were being added and placed correctly on the stage, but the incorrect “dealing” of the cards (their goofy ordering) was messing with the gesture recognizers, even as I specifically defined the layout, frame, and the gestures.

(Partial) Explanation:

Dictionaries are not ordered

The problem is that “hand” is not an array. It is a dictionary. And dictionaries are not ordered:

dictionary stores associations between keys of the same type and values of the same type in a collection with no defined ordering.

What I needed to do was order the dictionary by “key” so that cards would be “dealt” from left to right. One way would be to save the “hands” in an array. But there were good reasons I wanted the cards in a dictionary (easier and less expensive ordering and randomizing because I I can easily do those things on the “keys” of the dictionary as opposed to a string array).

Solution

So I came up with two solutions, both of which worked.

Use a for loop with an index

Loop through the hand in order from lowest to highest, specifically asking for each item in the dictionary by its index:

Pay attention to the “insertSubview…atIndex”. The above does two things:

  1. Orders the dealing of cards from left to right by calling each item in hand by its index
  2. Inserts every new card “over/after” the one before it.

Long story short, this fixed the problem of the overlapping views. I’m not sure of the reason: It doesn’t make sense to me that making this one change should not have an effect, but it did. My guess is that it is something about “atIndex” that fixed it (instead of, for example, front.layout.zPosition = key).

User the dictionary and then use a for-in loop

Another way to do this would be to order the indices in the dictionary first. It was bothering me, so I actually ended up doing this. Here’s how (no idea which way is faster or better):

Instructions

If you need instructions on how to use this code, see this post.

Leave a Reply

Your email address will not be published. Required fields are marked *


*