为 UIView 创建子类以实现可重用性

Creating a subclass for a UIView for reusability

我有一个 DiscoverViewController.h 和 .m 文件,它们具有替换要发现的地方的视图的功能。我也想在输出视图控制器中重用这个视图。 DicoverViewController.m 和 的代码如下:

for (PFObject *views in objects)
{
  // Get the discoverr view setup
  CGRect frame = CGRectMake(5.0, _viewStart, 310.0, viewHeight);

  DiscoverView *parent = [[DiscoverView alloc] init];

  [parent buildDiscoverViewWithFrame:frame andObjects:replies];
  // UIView *parent = [[UIView alloc] initWithFrame:CGRectMake(5.0, _viewStart, 310.0, viewHeight)];
  parent.backgroundColor = [UIColor whiteColor];
  // parent.layer.cornerRadius = 2.0;
  parent.layer.borderColor = [UIColor regularColor].CGColor;
  parent.layer.borderWidth = 1.0f;
  parent.tag = 1000 + _step;

  // Add the label counter
  // Add discover id for testing (is unique id)
  UILabel *placeholder = [[UILabel alloc] initWithFrame:CGRectMake(0.0, 10.0, 310.0, 12.0)];
  placeholder.backgroundColor = [UIColor clearColor];
  placeholder.textAlignment =  NSTextAlignmentCenter;
  placeholder.textColor = [UIColor bestTextColor];
  placeholder.font = [UIFont fontWithName:@"HelveticaNeue-Light" size:(12.0)];
  placeholder.Text = [NSString stringWithFormat:@"%@", views.objectId];

  [parent addSubview:placeholder];

  // Increase size of content view
  CGRect newContentView = _contentView.frame;

  newContentView.size.width = _contentView.frame.size.width;
  newContentView.size.height = _contentView.frame.size.height + bestHeight;

  [_contentView setFrame:newContentView];

  [_contentView addSubview:parent];

  scrollView.contentSize = _contentView.frame.size;

  // Adjust the postions
  _viewStart = _viewStart + viewHeight - 1.0;
  _step = _step + 1;
}                 

class叫DiscoverView.h

#import <UIKit/UIKit.h>
#import <Parse/Parse.h>

@interface DiscoverView : UIView

- (UIView *) buildDiscoverViewWithFrame:(CGRect) frame andObjects:(PFObject *) objects;

@end

实现文件DiscoverView.m:

- (UIView *) buildDiscoverViewWithFrame:(CGRect) frame andObjects:(PFObject *) objects
{
    UIView *discover = [[UIView alloc] initWithFrame:frame];

    _photoObject = objects.objectId;

    //Add a gesture to dismiss keyboard on tap
    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(discoverTapPressed)];

    [discover addGestureRecognizer:tap];

    return discover;
}

- (void) discoverTapPressed
{
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"The id is:"
                                                message:_photoObject
                                               delegate:nil
                                      cancelButtonTitle:@"OK"
                                      otherButtonTitles:nil];
    [alert show];
}

不知何故这无法正常工作。框架不会显示在右侧 space 并且点击根本不起作用。我是否需要将其更改为 class 引用而不是实例?如何重复使用此 class (DiscoverView) 并使其正常工作?

谢谢。

你的想法很好,我认为你的方法是对的......你只是犯了一些错误:

- (UIView *)buildDiscoverViewWithFrame:(CGRect) frame andObjects:(PFObject *) objects
{
    //Your method name is buildDiscoverView, but you are making a view
    //that is not a DiscoverView class. 
    UIView *discover = [[UIView alloc] initWithFrame:frame];

    //Tap gesture stuff...

    return discover;
}

并且:

DiscoverView *parent = [[DiscoverView alloc] init];

//parent will not contain an attached tap gesture, but the view 
//returned from its method does...
[parent buildDiscoverViewWithFrame:frame andObjects:replies];

//Ex:
//UIView *viewWithYourTapGesture = [parent buildDiscoverViewWithFrame:frame andObjects:replies];

我很确定这不是您真正想要的。我认为您正在尝试构建一个 DiscoveryView 实例,对吗?你可以这样做:

在你的DiscoveryView.m

- (id)initWithFrame:(CGRect)frame andObjects:(PFObject *)objects {

    //You can call initWithFrame: method here as our base constructor
    self = [super initWithFrame:frame];

    if (self) {

        //Add tap gesture here
        UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(discoverTapPressed)];
        [self addGestureRecognizer:tap];

        //and maybe do some other stuff as changing the background color
        //or making the border stuff that you are doing outside...
    }

    return self;
}

现在您可以按如下方式初始化您的实例:

在你的DiscoverViewController.m

DiscoverView *parent = [[DiscoverView alloc] initWithFrame:frame andObjects:replies];

//If you do this on init, you don't need this anymore...
//parent.backgroundColor = [UIColor whiteColor];
//parent.layer.cornerRadius = 2.0;
//parent.layer.borderColor = [UIColor regularColor].CGColor;
//parent.layer.borderWidth = 1.0f;

仅供参考:我还建议您检查新的 IBDesignable 功能,它允许我们直接从情节提要中可视化结果(但这不是您在此线程中要求的。)

更新:

正如@abhishekkharwar 所说,还有许多其他方法可以更好地做到这一点,例如使用 UICollectionViewUITableView,但您必须决定哪种方法更适合您的应用程序需求。尽量不要重新发明轮子。

将名为 DiscoverView.h 的 UIView class 更改为

- (id)initWithFrame:(CGRect)frame andObjects:(PFObject *)objects;

将实现文件 DiscoverView.m 更改为:

@interface DiscoverView ()
@property (nonatomic, strong) id photoObject;
@end
@implementation DiscoverView

- (id)initWithFrame:(CGRect)frame andObjects:(PFObject *)objects {

    //You can call initWithFrame: method here as our base constructor
    self = [super initWithFrame:frame];

    if (self) {

        UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(discoverTapPressed)];
        [self addGestureRecognizer:tap];
        _photoObject = objects.objectId;
        self.backgroundColor = [UIColor whiteColor];
        self.layer.cornerRadius = 2.0;
        self.layer.borderColor = [UIColor redColor].CGColor;
        self.layer.borderWidth = 1.0f;
    }

    return self;
}

- (void) discoverTapPressed
{
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"The id is:"
                                                    message:_photoObject
                                                   delegate:nil
                                          cancelButtonTitle:@"OK"
                                          otherButtonTitles:nil];
    [alert show];
}

替换旧代码中的代码:

   DiscoverView *parent = [[DiscoverView alloc] init];
  [parent buildDiscoverViewWithFrame:frame andObjects:replies];
  // UIView *parent = [[UIView alloc] initWithFrame:CGRectMake(5.0, _viewStart, 310.0, viewHeight)];
  parent.backgroundColor = [UIColor whiteColor];
  // parent.layer.cornerRadius = 2.0;
  parent.layer.borderColor = [UIColor regularColor].CGColor;
  parent.layer.borderWidth = 1.0f;
  parent.tag = 1000 + _step;

    DiscoverView *parent = [[DiscoverView alloc] initWithFrame:frame andObjects:replies];
    parent.tag = 1000 + _step;