DZNEmptyDataSet icon indicating copy to clipboard operation
DZNEmptyDataSet copied to clipboard

Button tap on custom view

Open whitefoxy opened this issue 9 years ago • 22 comments

I have created custom view for Empty tableview and there is a button which can be tapped, but problem is that button not recognize any touch it is like a static element.

Button have:

button.addTarget(self, action: #selector(TestController.buttonTap(_:)), forControlEvents: UIControlEvents.TouchUpInside)

Also I have added:

func emptyDataSetShouldAllowTouch(scrollView: UIScrollView!) -> Bool {
    return true
}

And the method emptyDataSetDidTapView also is not called, when I am touching the view.

How can I make a button touchable?

whitefoxy avatar May 25 '16 10:05 whitefoxy

I have the same problem. I searched in the closed issues and found out that the author had claimed fixing this but I can't make it work. I'm using the latest version from Cocoapods

ghost avatar May 26 '16 08:05 ghost

I have the same problem.

sasojadrovski avatar May 26 '16 14:05 sasojadrovski

I have the same issue. It works alright in version 1.7.3

martinciu avatar May 28 '16 11:05 martinciu

i submit an issues #265 ,you will know why button can't tap on customView.

xumoyan avatar May 30 '16 08:05 xumoyan

Hey @dzenbot,

Could you please take a look at this? For some reason if a custom view is used, and a button is present inside the custom view, the tap event is not transferred.

For some reason the UITableViewWrapperView is above the custom view and therefore the tap event is not triggered. The hitTest is invoked, but it cannot find the UIControl i.e. the UIButton that is tapped.

Removing this line

[self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[customView]|" options:0 metrics:nil views:@{@"customView":_customView}]];

puts the custom view to the bottom of the UIScrollView, and "solves" the problem, but of course, this behaviour is not something that we all want.

Thanks in advance for looking into this. Any feedback is appreciated!

Cheers, Sasho

sasojadrovski avatar Jun 10 '16 10:06 sasojadrovski

Running into the same issue. " UIView *hitView = [super hitTest:point withEvent:event]; " hitView is DZNEmptyDataSetView itself.

coderxdotwang avatar Jun 13 '16 07:06 coderxdotwang

I had run into the same problem, and I used the author's fix and solved the problem. Thanks dzenbot!

DaiYue avatar Jun 23 '16 10:06 DaiYue

As per checking based on @FunnyCoderWang 's comment. I noticed that when using a customView the height of contentView is zero. I think that's why the hitTest is giving UIView *hitView = DZNEmptyDataSetView

jcbernabe avatar Jul 22 '16 09:07 jcbernabe

Hi, @dzenbot , Could you fix the problem? The custom view's height is zero so the button on it can not be clicked.

jeffreylyg avatar Aug 08 '16 09:08 jeffreylyg

This has been a long standing bug, and haven't yet figure out a good way of fixing this from within the library. Instead, your custom view should override intrinsicContentSize if using auto-layout, and make sure that the view's height isn't zero, just like @jcbernabe stated.

dzenbot avatar Aug 17 '16 03:08 dzenbot

Change hitTest function like below code:

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
    if(_customView != nil){
        CGRect newFrame = _customView.frame;
        newFrame.size.height = self.frame.size.height;
        _customView.frame = newFrame;
        UIView *hitView = [_customView hitTest:point withEvent:event];
        return hitView;
    }else{
        UIView *hitView = [super hitTest:point withEvent:event];

        // Return any UIControl instance such as buttons, segmented controls, switches, etc.
        if ([hitView isKindOfClass:[UIControl class]]) {
            return hitView;
        }

        // Return either the contentView or customView
        if ([hitView isEqual:_contentView] || [hitView isEqual:_customView]) {
            return hitView;
        }
        return nil;
    }

}

thanhcao avatar Aug 27 '16 12:08 thanhcao

In case anybody wonders: the latest version of pods didn't fix the issue but code by @thanhcao did :)

backmeupplz avatar Sep 02 '16 05:09 backmeupplz

The last comment from @dzenbot is the real fix for this issue, given a custom view that uses auto-layout.

My case was a custom UIView subclass that was laid out as a NIB, and then loaded into -[CustomClass initWithFrame:] with -[NSBundle loadNibNamed:owner:options:].

My custom view had two embedded UIButton widgets, and none of them were responding to touches. I implemented intrinsicContentSize and that fixed the event handling issue:

- (CGSize)intrinsicContentSize
{
    return CGSizeMake(272.0f, 172.0f);
}

jpm avatar Sep 14 '16 18:09 jpm

2016.10.27 update Step1: Method -> setupConstraints add ->

NSLayoutConstraint *heightConstraint = [self equallyRelatedConstraintWithView:self.contentView attribute:NSLayoutAttributeHeight]; 

if (_customView) {
        [self addConstraint:heightConstraint];
    }

Step2: Method-> didMoveToSuperview add ->

if (_customView) {
        [self.superview bringSubviewToFront:self];
    }

Can fix this!

ad0ma avatar Sep 21 '16 04:09 ad0ma

For me the above suggestions did not suffice. The point's origin.y interfered with the hitTest on _customView. In order to fix this I altered the code a bit. Validated in two projects when setting a customView from code with no constraints. (_customView constraints unaltered.)

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
    if(_customView != nil){
        _customView.frame = self.frame;
        point = [super convertPoint:point toView:_customView];
        UIView *hitView = [_customView hitTest:point withEvent:event];
        return hitView;
    }else{
        UIView *hitView = [super hitTest:point withEvent:event];

        // Return any UIControl instance such as buttons, segmented controls, switches, etc.
        if ([hitView isKindOfClass:[UIControl class]]) {
            return hitView;
        }

        // Return either the contentView or customView
        if ([hitView isEqual:_contentView] || [hitView isEqual:_customView]) {
            return hitView;
        }
        return nil;
    }

}

rajderks avatar Nov 16 '16 06:11 rajderks

@jcbernabe

As per checking based on @FunnyCoderWang 's comment. I noticed that when using a customView the height of contentView is zero. I think that's why the hitTest is giving UIView *hitView = DZNEmptyDataSetView

When I read this comment I found the problem.

It's actually a common problem if you are creating a view from xib file which uses auto-layout.

If you are using auto layout you don't actually need to set height for root view, be sure that you have top and bottom constraints for each elements.

In my case I forgot to add bottom constraint for most bottom element, when I set zero (or 5 for padding) hitTest returns my button, and it all works.

So you don't need to override intrinsicContentSize.

okankocyigit avatar Mar 10 '17 12:03 okankocyigit

I have the same problem, and I watched layout of views, then I found the contentView has a error frame. In UIScrollView+EmptyDataSet.m contentView does not set up layout correctly. So, I change the code that starts at line 935 :

    // If applicable, set the custom view's constraints
    if (_customView) {
        // Complete setup the layout of contentView
        [self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[contentView]|" options:0 metrics:nil views:@{@"contentView": self.contentView}]];
        [self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[customView]|" options:0 metrics:nil views:@{@"customView":_customView}]];
        [self.contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[customView]|" options:0 metrics:nil views:@{@"customView":_customView}]];
    }

summertian4 avatar Jul 31 '17 08:07 summertian4

@martinciu was the fastest solution... downgraded the version to 1.7.3 and it started magically working

pmlbrito avatar Dec 13 '17 17:12 pmlbrito

@summertian4 give me a simple solution above. Now it works!!! Thanks!! Why has not this become a PR so far? Someone know?

romeugodoi avatar Apr 17 '18 14:04 romeugodoi

I implete with @jpm told, I have to set customView.userinteractionEnabled = NO; and delegate "emptyDataSet:didTapView:" will be resolve finally. If i add gesture or button, I test @rajderks 's advise ,then it success. current version: 1.8.1

akerdi avatar May 11 '18 09:05 akerdi

I'm just trying to keep this alive because it is a weird bug. I had two views, one was presenting problems, the other did not, constraints are almost similar, but i had to apply a override just like @jpm mentioned to jump the problem.

override var intrinsicContentSize: CGSize { return CGSize(width:bounds.width, height: bounds.height) }

Wilsonilo avatar Dec 26 '18 18:12 Wilsonilo

@jcbernabe

As per checking based on @FunnyCoderWang 's comment. I noticed that when using a customView the height of contentView is zero. I think that's why the hitTest is giving UIView *hitView = DZNEmptyDataSetView

When I read this comment I found the problem.

It's actually a common problem if you are creating a view from xib file which uses auto-layout.

If you are using auto layout you don't actually need to set height for root view, be sure that you have top and bottom constraints for each elements.

In my case I forgot to add bottom constraint for most bottom element, when I set zero (or 5 for padding) hitTest returns my button, and it all works.

So you don't need to override intrinsicContentSize.

Very good!

liubiaocong avatar Dec 29 '18 07:12 liubiaocong