How to use UITableView inside UIScrollView and rec

2019-01-09 07:56发布

问题:

I have DiscountListTableViewController that is shown as a separate screen in my app. But there's another screen (PlaceDetailsViewController) where I need to show related discounts at the bottom.

Currently, PlaceDetailsViewController.view has UIScrollView as a container and I'm adding DiscountListTableViewController.tableView to the this UIScrollView.content container in viewDidLoad of PlaceDetailsViewController. This works and the table view is shown correctly, however unable to receive cell clicks.

I know UITableView inherits from UIScrollView and it's somehow not advised (but not restricted). However, from loose coupling point of view, every component should be designed in a way it could be independently used elsewhere, and it's DiscountListTableViewController in my case.

PlaceDetailsViewController component just needs DiscountListTableViewController as-is, so there's no logic reason why it can't be used directly. Any suggestions?

回答1:

Answer : Don't do this.

UITableview is inherited from ----> UIScrollView : UIView : UIResponder : NSObject

Apple says :

Important: You should not embed UIWebView or UITableView objects in UIScrollView objects. If you do so, unexpected behavior can result because touch events for the two objects can be mixed up and wrongly handled.



回答2:

Not advised ? It kind of felt like "dont do" after reading this.The unpredictability is never a good behaviour for the app

Important: You should not embed UIWebView or UITableView objects in UIScrollView objects. If you do so, unexpected behavior can result because touch events for the two objects can be mixed up and wrongly handled.



回答3:

Will share how solved that. Did subclassed UIScrollView and used as container view in PlaceDetailsViewController:

@interface PlaceDetailsContainerUIScrollView : UIScrollView

@end

@implementation PlaceDetailsContainerUIScrollView

- (UIView*)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
  UIView *result = [super hitTest:point withEvent:event];

  if ([result isKindOfClass:[UIView class]] && (result.tag == kDiscountListTableViewCellTag)
  {
    UITableView *tableView = (UITableView *) [[result.superview superview] superview];

    return tableView;

  }

  return result;
}
@end

Also, don't forget to set PlaceDetailsContainerUIScrollView.delaysContentTouches = YES and PlaceDetailsContainerUIScrollView.canCancelContentTouches = NO.

Also, needed small fix in DiscountListTableViewController method:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
  DiscountDetailsViewController *discountDetailsVC = [[DiscountDetailsViewController alloc] init];

  //[self.navigationController pushViewController:discountDetailsVC animated:YES];   
  // self.navigationController is nill because it's not pushed on nav stack, so will grab the current one:
  AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];

  [appDelegate.navigationController pushViewController:discountDetailsVC animated:YES];
}


回答4:

Perhaps this is late, but I managed to do this by:

  • Disable Scroll on the UITableView
  • Set the content size of the UIScrollView programmatically after I calculate the height I need