I am familiar with using storyboards to construct UI elements in Xcode, but I am only beginning to learn how to make UI programmatically (without a storyboard).
I wanted to know if this is the correct way to implement a UIView into an existing ViewController class.
DetailView (Custom UIView class):
.h file (header)
@interface DetailView : UIView
@property (strong, nonatomic) UIImageView *imageView;
@property (strong, nonatomic) UIImageView *ratingView;
@property (strong, nonatomic) UILabel *tagLabel;
@property (strong, nonatomic) UILabel *plotLabel;
@end
.m file (implementation)
- (instancetype)init {
if(self = [super init]){
// Creating the large movie image
_imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0.0, 64.0, 375.0f, 200.0f)];
// Creating the rating image
_ratingView = [[UIImageView alloc] init];
// Creating the tag Label
_tagLabel = [[UILabel alloc] initWithFrame:CGRectMake(38, 274, 355, 200)];
self.tagLabel.font = [UIFont fontWithName:@"HelveticaNeue" size:12];
// Creating the plot label
_plotLabel = [[UILabel alloc] initWithFrame:CGRectMake(10, 299, 355, 200)];
self.plotLabel.font = [UIFont fontWithName:@"HelveticaNeue" size:14];
[self addSubview:self.imageView];
[self addSubview:self.ratingView];
[self addSubview:self.tagLabel];
[self addSubview:self.plotLabel];
}
return self;
}
View Controller:
Commented code is another way I attempted to implement the DetailView
- (void)viewDidLoad {
[super viewDidLoad];
self.detailView = [[DetailView alloc] init];
self.title = self.movie.title;
self.view.backgroundColor = [UIColor whiteColor];
self.detailView.imageView.image =
[UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:self.movie.fanArt]]];
//[self.view addSubview:self.detailView.imageView];
[self setRatingImage:self.movie.rating];
//[self.view addSubview:self.detailView.ratingView];
self.detailView.tagLabel.numberOfLines = 0;
self.detailView.tagLabel.text = self.movie.tagline;
[self.detailView.tagLabel sizeToFit];
//[self.view addSubview:self.detailView.tagLabel];
self.detailView.plotLabel.numberOfLines = 0;
self.detailView.plotLabel.text = self.movie.plot;
[self.detailView.plotLabel sizeToFit];
//[self.view addSubview:self.detailView.plotLabel];
[self.view addSubview:self.detailView];
}
-
\$\begingroup\$ Would you mind adding some detail as to why storyboards won't work for you? \$\endgroup\$nhgrif– nhgrif2014年10月24日 13:25:55 +00:00Commented Oct 24, 2014 at 13:25
-
1\$\begingroup\$ @nhgrif they work perfectly, I am just learning how to do it with code so I have a better understanding. \$\endgroup\$Jacob Young– Jacob Young2014年10月24日 15:22:14 +00:00Commented Oct 24, 2014 at 15:22
1 Answer 1
A couple of thoughts:
It is curious to do some of the configuration of the subview's within your custom class (e.g. the frames) and other portions (e.g.
numberOfLines
andsizeToFit
) in the view controller. If I were going to have thisUIView
subclass, then I'd encapsulate all the presentation details within that class. As it is, if the UI isn't quite right, you'll never quite know which class you have to take a look at.It is curious to use
numberOfLines
of zero, but then to use hard-codedframe
sizes. (Sure, yousizeToFit
, but don't adjust the origin.) If one label changes size, wouldn't you want to move the other controls accordingly? You might contemplate specifyingpreferredMaxLayoutWidth
, too.In this day and age of differing device dimensions, it is curious to see hard-coded
frame
sizes at all. I'd probably implement auto layout unless you had some compelling reason not to. And even if I didn't use auto layout, I'd still specify the autosizing masks.I generally give my subviews
weak
references because the process of doingaddSubview
already maintains a strong reference, and it's not clear your really need two strong references. (Clearly, you have to temporarily use a local variable when instantiating the label, if you go this route.)Clearly you're not contemplating it at this point, but let's say you ever wanted to do
[self.tagLabel removeFromParentView]
. Would you also want to have to remember to doself.tagLabel = nil
as well?It's not a big deal, but I tend to follow the NIB/storyboard model that I don't generally maintain strong references to subviews: The only strong reference I'd maintain would be to the root view.
You're never setting the
frame
for yourratingView
. I might confirm the clipping and content mode, too.If you're going to have this
UIView
subclass, it doesn't feel like the view controller should be playing around with which image to show in the rating view. The view controller should probably just tell theUIView
subclass what the rating is, and that subclass should take care of the presentation of the appropriate rating image.Rather than using fixed fonts, if this was an iOS 7+ target, I'd consider using Dynamic Type.
If
[NSURL URLWithString:self.movie.fanArt]
is in the local file system, you can get away with doing that main thread, but if it's a remote URL, then definite retrieve that image asynchronously.In terms of having custom
UIView
subclass at all, I'm not sure there's enough utility in this subview to warrant a subclass. Perhaps, once you start incorporating the above points, there might be enough substance to make this worth while, but I'm not sure your existing code sample justifies it.