maxkonovalov / MKDropdownMenu

🔻 Dropdown Menu for iOS with many customizable parameters to suit any needs
MIT License
524 stars 83 forks source link

I'd like to make a dimmed background for the whole view #5

Closed EddieLukeAtmey closed 8 years ago

EddieLukeAtmey commented 8 years ago

I've implemented your dropdown menu, subclass it as to fit my own theme. It works nice but there's something a little bit off when the drop down is not on top of a view (see image below)

simulator screen shot 2016 09 07 14 20 38

(Note: In the image I haven't set the presentingView to my popup, but I'll)

Please guide me about how to make the whole view dimmed and tapable (to dismiss the dropDown), or make an update or anything. Currently, I'm disabling the dimmed background as a work around, but it still not receive the tapAction when tap above the dropDown.

maxkonovalov commented 8 years ago

Hi @EddieLukeAtmey! The main idea for dismissing the dropdown is by tapping below it. For that purpose only the bottom part of the screen is dimmed. However, everything above the dropdown should still be interactable. You can see this in the table view part of the Example project. For your case I would suggest starting off by setting the presentingView as you mentioned, switch off the built-in dimming by setting backgroundDimmingOpacity to 0.0, and presenting your own dimming view under the dropdown. You can then add a tap gesture recognizer to your dimming view and dismiss the dropdown by calling -closeAllComponentsAnimated: in the recognizer's action. If you need more assistance with this, or if it doesn't work for you, please let me know.

EddieLukeAtmey commented 8 years ago

Hi @maxkonovalov

I'm trying your suggestion and get stuck somehow. The main idea is to subclass your MKDropDownMenu, not to customize your files (I used cocoa pod). I've successfully followed your steps here:

  1. set presentingView to the big view (the green + red part in the image).
  2. Set backgroundDimmingOpacity = 0

Now is the hard part: I add a UITapGestureRecognizer to the presentingView, trying to dismiss the dropDown when tap outside. Unfortunately, it dismisses the dropDown by tap on anywhere :(

- (void)setPresentingView:(UIView *)presentingView
{
    [super setPresentingView:presentingView];

    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)];
    tap.delegate = self;
    [presentingView addGestureRecognizer:tap];
}

- (void)handleTap:(UITapGestureRecognizer *)sender
{
    [self closeAllComponentsAnimated:YES];
}

Because the parent control (MKDropDownMenu) has a private controller which handle all these things, I can't find out how to make it work. At the very least, I just want to dismiss when tap anywhere outside the whole dropDown.

EddieLukeAtmey commented 8 years ago

Okay, I've finally managed to make it work as I wish by adding this work-around:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
    CGPoint location = [touch locationInView:self.presentingView];
    return location.y < CGRectGetMaxY(self.frame);
}

But I still don't feel satisfied yet. Do you have any other suggestion? or anything seems better?

maxkonovalov commented 8 years ago

@EddieLukeAtmey: my suggestion is to add a separate view between the dropdown menu and your presenting view, and use it for handling tap gestures and, optionally, for dimming the background. I did a test setup and it worked as expected for me.

Here's the code:

- (void)viewDidLoad {
    [super viewDidLoad];

    // dropdown setup...

    self.dimmingView = [[UIView alloc] initWithFrame:self.view.bounds];
    self.dimmingView.backgroundColor = [[UIColor greenColor] colorWithAlphaComponent:0.5];
    self.dimmingView.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;
    [self.view insertSubview:self.dimmingView belowSubview:self.dropdownMenu];

    [self.dimmingView addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)]];
}

- (void)handleTap:(id)sender {
    [self.dropdownMenu closeAllComponentsAnimated:YES];
}

-(void)dropdownMenu:(MKDropdownMenu *)dropdownMenu didOpenComponent:(NSInteger)component {
    self.dimmingView.hidden = NO;
}

- (void)dropdownMenu:(MKDropdownMenu *)dropdownMenu didCloseComponent:(NSInteger)component {
    // might need to track if all components have been closed here...
    self.dimmingView.hidden = YES;
}

If you are using a MKDropdownMenu subclass, you can move this logic there, just don't forget to cleanup your dimming view when you're done.

maxkonovalov commented 8 years ago

Here is a screenshot of my setup btw

simulator screen shot 08 sep 2016 11 38 43

The dimming view is shown in green, and the dropdown dismisses by tapping anywhere in green area only.

EddieLukeAtmey commented 8 years ago

Hi, Thanks for your response!!

It seems this may cause a lot of works each time I set up the dropDown and not reusable as a separated control. Like, if I have many VCs that use the dropDown, in each VC I'll have to setup the dimmed background and stuffs like that.

Another solution is to create the dimmingView for each dropDown when set the presentingView in the subclass control. But this may cause a lot of unnecessary subViews. I'm not sure which to choose, please suggest me.

maxkonovalov commented 8 years ago

As I suggested previously, you can add all the above code directly to your subclass so that you have a consistent behavior all over the app. And I don't think that adding another subview to the hierarchy would do any harm, especially taking into consideration that it should only be visible when the dropdown is shown.