UITableview/UIView 代表混乱

UITableview/UIView Delegate Confusion

我正在制作自己的下拉菜单,因为我找不到完全满足我需要的开源菜单。 我已经将下拉菜单实现为 ​​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。

注意:我知道动画失态是因为我没有使用更新的方法。这是基于旧的示例代码。问题解决后我会更新动画

问题:

  1. UIViews不能作为UITableView的Delegates是真的吗?

  2. 如果是这样,如何使调用视图控制器成为驻留在 UIView 中的 table 视图的委托?除了在创建 table.

  3. 时将其设置为 UITableViewDelegate 并将调用视图控制器分配为委托的过程之外
  4. 我是不是错过了我设置它的方式中的某些东西,它窃取了 cell tap,这样 didSelect 就不会被调用,无论是在视图中还是在 viewController 中?

感谢您的帮助。

如我所见,您正在将 ViewController(它是 MenuViewDelegate)传递给 showDropDownWith 方法,然后将其用作 table 委托。这是不正确的。

你应该在那里传递 self(与数据源相同),因为你希望 MenuView 成为 table 的代表,而不是 ViewController,对吗?

self.table.delegate = self;

同意@Piotr 的观点,菜单必须是table 的委托,因此在MenuView.m 中将self.table.delegate = delegate; 替换为self.table.delegate = self;

但另外,MenuView.m 从不调用 它的委托 ,它应该在 table 视图中选择....

- (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];

另一种选择是将选定的字符串交还给委托。这可以在 table 视图的数据源中找到 indexPath.row。

最后,最好不要保留您的代表,因为菜单的客户可能会保留它,从而导致保留周期。相反,声明委托:

// notice "weak"
@property (nonatomic, weak) id <MenuViewDelegate> delegate;