cdub
cdub

Reputation: 25701

Creating a subclass for a UIView for reusability

I have a DiscoverViewController.h and .m files that have a function that displaces views of places to discover. I want to reuse this view in output viewcontrollers too. The code for the DicoverViewController.m with the is below:

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;
}                 

The class called DiscoverView.h

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

@interface DiscoverView : UIView

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

@end

The implementation file 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];
}

Somehow this is not working correctly. The frame won't show in the right space and the tap doesn't work at all. Do I need to change it to be a class reference vs an instance? How do I reuse this class (DiscoverView) and get this working properly?

Thanks.

Upvotes: 0

Views: 1328

Answers (2)

ChenYilong
ChenYilong

Reputation: 8673

Change the UIView class called DiscoverView.h to

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

change the implementation file DiscoverView.m to :

@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];
}

Replace the code in your old code:

   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;

to

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

Upvotes: 1

FormigaNinja
FormigaNinja

Reputation: 1571

Your idea is very good and I think you are on the right way ... you just had made some mistakes:

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

And:

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

I 'm pretty sure that it's not what you really want. I think you are trying to build a DiscoveryView instance instead right? you can do it this way:

On your 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;
}

Now you can init your instance as below:

On your 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;

FYI: I also recommend you to check the new IBDesignable feature, that allow us to visualize the results directly from Storyboard (but it's NOT what you are asking for on this thread.)

Update:

As @abhishekkharwar said, there are many other ways to do this better, as using UICollectionView or UITableView, but you have to decide what fits better on your app needs. Just try NOT to re-invent the wheel.

Upvotes: 1

Related Questions