UITableview/UIView 委托混淆
Posted
技术标签:
【中文标题】UITableview/UIView 委托混淆【英文标题】:UITableview/UIView Delegate Confusion 【发布时间】:2015-05-26 17:20:30 【问题描述】:我正在制作自己的下拉菜单,因为我无法找到完全符合我需要的开源菜单。 我已将下拉菜单实现为 UIView,并将其添加到被点击的按钮的超级视图中以显示它。
代码:
ViewController.m
#import "ViewController.h"
#import "MenuView.h"
@interface ViewController () <MenuViewDelegate>
@property (weak, nonatomic) IBOutlet UIView *fakeHeader;
@property (nonatomic, strong) MenuView *menuView;
@end
@implementation ViewController
- (void)viewDidLoad
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
- (void)didReceiveMemoryWarning
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
- (IBAction)btnTapped:(id)sender
NSArray *array = @[@"Item 1", @"Item 2", @"Item 3", @"Item 4"];
NSArray *imgArray = nil;
if (self.menuView == nil)
self.menuView = [[MenuView alloc] showDropDownWith:sender txtArr:array imgArr:imgArray direction:@"down" delegate:self];
self.menuView.delegate = self;
else
[self.menuView hideDropDown:sender];
self.menuView = nil;
- (void) menuDelegateMethod:(MenuView *)sender
self.menuView = nil;
@end
MenuView.h
#import <UIKit/UIKit.h>
@class MenuView;
@protocol MenuViewDelegate
- (void)menuDelegateMethod:(MenuView *)sender;
@end
@interface MenuView : UIView
@property (nonatomic, retain) id <MenuViewDelegate> delegate;
- (id)showDropDownWith:(UIButton *)button txtArr:(NSArray *)txtArr imgArr:(NSArray *)imgArr direction:(NSString *)direction delegate:(id)delegate;
- (void)hideDropDown:(UIButton *)button;
@end
MenuView.m
#import "MenuView.h"
#import "QuartzCore/QuartzCore.h"
@interface MenuView () <UITableViewDataSource, UITableViewDelegate>
@property (nonatomic, strong) UITableView *table;
@property (nonatomic, strong) UIButton *btnSender;
@property (nonatomic, retain) NSString *animationDirection;
@property (nonatomic, retain) NSArray *list;
@property (nonatomic, retain) NSArray *imageList;
@end
@implementation MenuView
- (id)showDropDownWith:(UIButton *)button txtArr:(NSArray *)txtArr imgArr:(NSArray *)imgArr direction:(NSString *)direction delegate:(id)delegate
CGFloat width = [UIScreen mainScreen].bounds.size.width;
CGFloat origin = [UIScreen mainScreen].bounds.origin.x;
CGFloat realHeight = 40 * txtArr.count;
self.btnSender = button;
self.animationDirection = direction;
self.table = (UITableView *)[super init];
if (self)
// Initialization code
CGRect btn = button.frame;
self.list = [NSArray arrayWithArray:txtArr];
self.imageList = [NSArray arrayWithArray:imgArr];
if ([direction isEqualToString:@"up"])
self.frame = CGRectMake(origin, (btn.origin.y - btn.size.height) , width, 0);
self.layer.shadowOffset = CGSizeMake(0, 1);
else if ([direction isEqualToString:@"down"])
self.frame = CGRectMake(origin, (btn.origin.y + btn.size.height + 10), width, 0);
self.layer.shadowOffset = CGSizeMake(0, 1);
self.layer.masksToBounds = YES;
self.layer.shadowOpacity = 0.2;
self.table = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, width, 0)];
self.table.delegate = delegate;
self.table.dataSource = self;
self.table.backgroundColor = [UIColor colorWithRed:0.239 green:0.239 blue:0.239 alpha:1];
self.table.separatorStyle = UITableViewCellSeparatorStyleSingleLine;
self.table.separatorColor = [UIColor lightGrayColor];
self.table.backgroundColor = [UIColor whiteColor];
self.table.userInteractionEnabled = YES;
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.5];
if ([direction isEqualToString:@"up"])
self.frame = CGRectMake(origin, (btn.origin.y - realHeight), width, realHeight);
else if([direction isEqualToString:@"down"])
self.frame = CGRectMake(origin, (btn.origin.y + btn.size.height + 10), width, realHeight);
self.table.frame = CGRectMake(0, 0, width, realHeight);
[UIView commitAnimations];
[button.superview addSubview:self];
self.table.tableFooterView = [[UIView alloc] initWithFrame:CGRectZero];
[self addSubview:self.table];
return self;
- (void)hideDropDown:(UIButton *)button
CGRect btn = button.frame;
CGFloat width = [UIScreen mainScreen].bounds.size.width;
CGFloat origin = [UIScreen mainScreen].bounds.origin.x;
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.5];
if ([self.animationDirection isEqualToString:@"up"])
self.frame = CGRectMake(origin, btn.origin.y, width, 0);
else if ([self.animationDirection isEqualToString:@"down"])
self.frame = CGRectMake(origin, (btn.origin.y + btn.size.height + 10), width, 0);
self.table.frame = CGRectMake(0, 0, width, 0);
[UIView commitAnimations];
#pragma mark - Table View DataSource
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
return 1;
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
return [self.list count];
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
cell.textLabel.font = [UIFont systemFontOfSize:15];
cell.textLabel.textAlignment = NSTextAlignmentLeft;
cell.textLabel.text = [self.list objectAtIndex:indexPath.row];
cell.backgroundColor = [UIColor colorWithRed:48.0f/255.0f green:48.0f/255.0f blue:48.0f/255.0f alpha:1.0f];
cell.textLabel.textColor = [UIColor lightTextColor];
return cell;
#pragma mark - Table View Delegate
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
return 40;
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
[self hideDropDown:self.btnSender];
[self myDelegate];
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
// Remove seperator inset
if ([cell respondsToSelector:@selector(setSeparatorInset:)])
[cell setSeparatorInset:UIEdgeInsetsZero];
// Prevent the cell from inheriting the Table View's margin settings
if ([cell respondsToSelector:@selector(setPreservesSuperviewLayoutMargins:)])
[cell setPreservesSuperviewLayoutMargins:NO];
// Explictly set your cell's layout margins
if ([cell respondsToSelector:@selector(setLayoutMargins:)])
[cell setLayoutMargins:UIEdgeInsetsZero];
#pragma mark - View Delegate
- (void)myDelegate
[self.delegate menuDelegateMethod:self];
@end
完美显示,但从不调用 didSelect 方法。
我没有任何关于它会窃取触摸事件的观点。
似乎 UIViews 可能无法成为 UITableviewDelegates。如果这是真的,我不知道为什么,当我将调用视图控制器设为委托时,它仍然无法 didSelect。
注意:我知道不使用较新方法的动画失礼。这是基于旧的示例代码。解决这个问题后我会更新动画。
问题:
难道UIViews不能是UITableView Delegates吗?
如果是这样,如何使调用视图控制器成为驻留在 UIView 中的表视图的委托?除了将其设置为 UITableViewDelegate 并在创建表时将调用视图控制器分配为委托的过程。
我是否在设置此方法时遗漏了某些东西,该方法窃取了单元格点击,从而不会在视图或 viewController 中调用 didSelect?
感谢您的帮助。
【问题讨论】:
【参考方案1】:同意@Piotr 的菜单必须是表的委托,所以在MenuView.m 中将self.table.delegate = delegate;
替换为self.table.delegate = self;
。
但另外,MenuView.m 从不调用 它的委托,它应该在 tableview 中选择时调用....
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
[self hideDropDown:self.btnSender];
// remove this, since it does nothing
//[self myDelegate];
// replace it with
[self.myDelegate menuDelegateMethod:self];
最后一行说,告诉菜单的代表发生了什么事。
另一个问题是菜单并没有真正告诉委托人发生了什么。当然,代表会对选择哪个项目感兴趣。考虑将协议更改为:
@protocol MenuViewDelegate
- (void)menuView:(MenuView *)sender didSelectOptionAtIndex:(NSInteger)index;
@end
// calling it
[self.myDelegate menuView:self didSelectOptionAtIndex:indexPath.row];
另一种选择是将选定的字符串交还给委托人。这可以在 indexPath.row 的 tableview 的数据源中找到。
最后,最好不要保留您的代表,因为菜单的客户可能会保留它,从而导致保留周期。相反,声明委托:
// notice "weak"
@property (nonatomic, weak) id <MenuViewDelegate> delegate;
【讨论】:
问题是[self.myDelegate menuDelegateMethod:self];永远不会被调用,因为即使使用 self.table.delegate = self; idSelectRowAtIndexPath 永远不会被调用。不知何故,并非所有的委托方法都在 MenuView 中被调用。 我刚刚重新阅读了 showDropDownWith 方法。我没有意识到这是一个 init 方法。该代码打破了一些基本约定,例如它不调用self = [super init];
。请在顶部添加,并删除无意义的行 self.table = (UITableView *)[super init];
请确保将 self.table 委托和数据源设置为 self。
Piotr 和 danh 都有正确的答案。但是danh给出了更详细的帮助。但是,最后我发现我的方法有很多问题,我不得不重新编写它。总的教训是,没有人应该认为他们可以免于观察适当的视图层次结构。这就是我的大部分问题所在。【参考方案2】:
如我所见,您将ViewController
(它是MenuViewDelegate
)传递给showDropDownWith
方法,然后将其用作表委托。这是不正确的。
您应该在那里传递self
(与数据源相同),因为您希望MenuView
成为表的代表,而不是ViewController
,对吧?
self.table.delegate = self;
【讨论】:
以上是关于UITableview/UIView 委托混淆的主要内容,如果未能解决你的问题,请参考以下文章