I have a custom view called TimeTooltipView. Here is the code:
TimeTooltipView.h
#import <UIKit/UIKit.h>
#interface TimeTooltipView : UIView
#property (weak, nonatomic) IBOutlet UILabel *timeLabel;
-(void)configureView;
#end
TimeTooltipView.m
#import "TimeTooltipView.h"
#implementation TimeTooltipView
-(id)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
NSArray *subviewArray = [[NSBundle mainBundle] loadNibNamed:#"TimeTooltipView" owner:self options:nil];
UIView *mainView = [subviewArray objectAtIndex:0];
[self addSubview:mainView];
[self configureView];
}
return self;
}
-(void)configureView {
self.backgroundColor = [UIColor greenColor];
}
#end
I add a TimeTooltipView in a view controller, like so:
TimeTooltipView *timeTooltipView = [[TimeTooltipView alloc]
initWithFrame: CGRectMake(100, 100, 50, 50)];
timeTooltipView.timeLabel.text = #"TEST";
[self.view addSubview:timeTooltipView];
timeTooltipView.timeLabel.text = #"TEST2";
I need to change timeLabel's text on the fly from the view controller. Using the code above, the view gets added and has a green background color. But the label text never changes to "TEST" or "TEST2".
How can I change the custom view's label text on the fly?
-(id)initWithFrame:(CGRect)frame {
NSArray *subviewArray = [[NSBundle mainBundle] loadNibNamed:#"TimeTooltipView" owner:self options:nil];
//Instead of making it subView just replace it.
self = [subviewArray objectAtIndex:0];
self.frame = frame;
[self configureView];
return self;
}
-(void)configureView {
self.backgroundColor = [UIColor greenColor];
}
Related
I have 4 screens that have one almost the same view:
And one screen have the same view but with slightly different UI:
So, my question: Can I use one xib and adapt states (active, inactive) and change ui for different screen? How I can do it?
Here is an example of this kind of class
In Your .m file of custom XIB class if you are using objective-c.
- (void)foo:(NSString*)labelText andButtonText:(NSString*)buttonTitle {
//Do your code here for some screen like change labels and button text
}
- (void)bar:(NSString*)labelText andButtonText:(NSString*)buttonTitle {
//Do your code here for some another screen and change labels and button text
}
In Your .h file of custom XIB class if you are using objective-c.
- (void)foo:(NSString*)labelText andButtonText:(NSString*)buttonTitle;
- (void)bar:(NSString*)labelText andButtonText:(NSString*)buttonTitle;
In your view controller where you want to display the custom UI
Create an instance of your xib or add through interfacebuilder
And On your instance of custom class call the method as required.
Below is a class I've used in one of my project to get a clear understanding.
#import <UIKit/UIKit.h>
#import "DYRateView.h"
#interface LevelAndRankDetails : UIView
#property (nonatomic, strong) IBOutlet UIView* contentView;
#property (nonatomic, strong) IBOutlet UIView* viewContainer;
#property (nonatomic, strong) IBOutlet UILabel* lblLevel;
#property (nonatomic, strong) IBOutlet UILabel* lblRanking;
#property (weak, nonatomic) IBOutlet DYRateView *viewRate;
- (void)setLevel:(NSNumber*)level andRanking:(NSNumber*)ranking;
- (void)setupUI;
#end
.m File
#import "LevelAndRankDetails.h"
#import "AppDelegate.h"
#import "Constants.h"
#implementation LevelAndRankDetails
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
// Drawing code
}
*/
- (id)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]){
[self commonSetup];
}
return self;
}
-(id)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self)
{
[self commonSetup];
}
return self;
}
- (void)layoutSubviews {
[super layoutSubviews];
}
- (void)viewFromNibForClass {
[[NSBundle mainBundle] loadNibNamed:[[self class] description] owner:self options:nil];
[self addSubview:self.contentView];
self.contentView.frame = self.bounds;
}
- (void)commonSetup {
[self viewFromNibForClass];
//For View's Corner Radius
self.contentView.layer.cornerRadius = 12;
self.contentView.layer.masksToBounds = YES;
self.contentView.backgroundColor = kDefaultBackgroundGreyColor;
self.viewContainer.backgroundColor = kDefaultBackgroundGreyColor;//[UIColor clearColor];
self.backgroundColor = kDefaultBackgroundGreyColor;
//self.viewContainer.backgroundColor = UIColorFromRGB(0xBB9657);//[kLearnFromLightColor colorWithAlphaComponent:0.5];
self.viewRate.rate = 0;
self.viewRate.editable = NO;
self.viewRate.delegate = nil;
self.viewRate.alignment = RateViewAlignmentCenter;
self.viewRate.backgroundColor = [UIColor clearColor];
[self.viewRate setEmptyStarImage:[UIImage imageNamed:#"StarEmpty"]];
UIImage* imageFullStar = [[UIImage imageNamed:#"StarFull"] imageTintedWithColor:kSliderDarkYellowColor];
[self.viewRate setFullStarImage:imageFullStar];
self.lblLevel.textColor = [UIColor whiteColor];
self.lblRanking.textColor = [UIColor whiteColor];
//For Teacher label
}
- (void)setupUI {
self.contentView.layer.cornerRadius = 0;
self.contentView.layer.masksToBounds = YES;
self.contentView.backgroundColor = [UIColor clearColor];
self.viewContainer.backgroundColor = [UIColor clearColor];//[UIColor clearColor];
self.backgroundColor = [UIColor clearColor];
}
- (void)setRanking:(CGFloat)ranking {
self.viewRate.rate = ranking;
}
- (void)setLevel:(NSNumber*)level {
self.lblLevel.text = [NSString stringWithFormat:#"Level : %#",level];
}
- (void)setLevel:(NSNumber*)level andRanking:(NSNumber*)ranking {
if (level.integerValue > 0) {
[self setLevel:level];
}
if (ranking.doubleValue > 0) {
CGFloat rankingConverted = ranking.floatValue;
[self setRanking:rankingConverted];
}
}
#end
And this is how you use it in your view controller
LevelAndRankDetails* toolTipCustomView = [[LevelAndRankDetails alloc] initWithFrame:CGRectMake(0, 0, 250, 66)];
toolTipCustomView.backgroundColor = [UIColor blackColor];
[toolTipCustomView setLevel:#(10) andRanking:#(3)];
I have created a custom view and added a UITextField to it.My question is: How can I add a delegate so that the you can set it as the default cmd+drag behaviour of XCode?
My current attempt is by doing something like this:
In my .h file:
#import <UIKit/UIKit.h>
IB_DESIGNABLE
#interface CustomTextField : UIView
#property (assign, nonatomic) IBInspectable id textFieldDelegate;
#end
and my .m file:
#import "CustomTextField.h"
#interface CustomTextField()
#property (strong, nonatomic) IBOutlet UITextField *textField;
#end
#implementation CustomTextField
- (instancetype)initWithFrame:(CGRect)frame{
if (self = [super initWithFrame:frame]) {
[self loadNib];
}
return self;
}
- (void)loadNib{
UIView *view = [[[NSBundle bundleForClass:[self class]] loadNibNamed:#"CustomTextField" owner:self options:nil] firstObject];
[self addSubview:view];
view.frame = self.bounds;
}
- (void)setTextFieldDelegate:(id)textFieldDelegate{
self.textField.delegate = textFieldDelegate;
}
#end
But it doest show up in the left panel of XCode, Connections Inspector Tab.
Also here is my current code.
Update 1:
also if using the code below I get a an error:
- (id)initWithFrame:(CGRect)aRect
{
self = [super initWithFrame:aRect];
if (self)
{
[self loadNib];
}
return self;
}
- (id)initWithCoder:(NSCoder*)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self)
{
[self loadNib];
}
return self;
}
- (void)loadNib{
//
// UIView *view = [[[NSBundle bundleForClass:[self class]] loadNibNamed:#"CustomTextField" owner:self options:nil] firstObject];
// [self addSubview:view];
// view.frame = self.bounds;
UIView *view = [[[NSBundle bundleForClass:[self class]] loadNibNamed:#"CustomTextField" owner:self options:nil] firstObject];
[view setTranslatesAutoresizingMaskIntoConstraints:NO];
[self addSubview:view];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[view]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(view)]];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[view]|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(view)]];
self.textLabel.text = #"1";
}
Any suggestions on what should I do?
Update 2
I ended up by replacing the initWithFrame, initWithCoder and loadNib functions with:
- (id)awakeAfterUsingCoder:(NSCoder *)aDecoder
{
if (![self.subviews count])
{
NSBundle *mainBundle = [NSBundle mainBundle];
NSArray *loadedViews = [mainBundle loadNibNamed:#"CustomTextField" owner:nil options:nil];
CustomTextField *loadedView = [loadedViews firstObject];
loadedView.frame = self.frame;
loadedView.autoresizingMask = self.autoresizingMask;
loadedView.translatesAutoresizingMaskIntoConstraints =
self.translatesAutoresizingMaskIntoConstraints;
for (NSLayoutConstraint *constraint in self.constraints)
{
id firstItem = constraint.firstItem;
if (firstItem == self)
{
firstItem = loadedView;
}
id secondItem = constraint.secondItem;
if (secondItem == self)
{
secondItem = loadedView;
}
[loadedView addConstraint:
[NSLayoutConstraint constraintWithItem:firstItem
attribute:constraint.firstAttribute
relatedBy:constraint.relation
toItem:secondItem
attribute:constraint.secondAttribute
multiplier:constraint.multiplier
constant:constraint.constant]];
}
return loadedView;
}
return self;
}
I am having huge problems with learning autolayout especially when integrating xibs and uiscrollviews. In an effort to simplify my problem, I started a new project with a single view tied to a storyboard. I then subclassed UIView (Diptic) and created a xib file for it. My storyboard is not using autolayout, but my Diptic xib is. Right now I want to have a horizontal scrollView with a few Diptic instances layed out across it. But I am only ever getting the first diptic instance to show up, because the frame isn't being initialized correctly.
In my ViewController.m's viewDidLoad:
self.scrollView.contentSize = CGSizeMake((self.view.frame.size.width+10)*5, self.view.frame.size.height);
for (int i = 0; i < 5; i++){
int x = i*(self.view.frame.size.width+10);
Diptic *diptic = [[Diptic alloc] initWithFrame:CGRectMake(x, 50, self.view.frame.size.width, self.view.frame.size.height-100)];
[self.scrollView addSubview:diptic];
[array addObject:diptic];
UIView *greenBox = [[UIView alloc] initWithFrame:CGRectMake(x, 5, 40, 40)];
greenBox.backgroundColor = [UIColor greenColor];
[self.scrollView addSubview:greenBox];
}
Diptic.m
#import "Diptic.h"
#implementation Diptic
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
NSArray* views = [[NSBundle mainBundle] loadNibNamed:#"Diptic" owner:nil options:nil];
self = [views objectAtIndex:0];
self.label.text = #"WOOT";
self.backgroundColor = [UIColor redColor];
}
return self;
}
#end
If I set the frame after I add it to the view it seems to work, but why can't I set the frame with initWithFrame?
The problem here is that you assign the frame to a view that is created with a call to [super initWithFrame:frame]. When the NIB is loaded in - (id)initWithFrame:(CGRect)frame, self is replaced with a view from [views objectAtIndex:0] and the frame for this view is never set. Instead, eliminate the call to super and load the view from the NIB instead:
#import "Diptic.h"
#implementation Diptic
- (id)initWithFrame:(CGRect)frame
{
NSArray *views = [[NSBundle mainBundle] loadNibNamed:#"Diptic" owner:nil options:nil];
self = [views objectAtIndex:0];
if (self) {
self.frame = frame;
self.label.text = #"WOOT";
self.backgroundColor = [UIColor redColor];
}
return self;
}
#end
When init a view/controller from storyboard or from xib, the init method is
- (id)initWithCoder:(NSCoder *)decoder
try to do other things in this method
I created a .xib file form my custom view.
I created .h/.m files for that view.
I ctrl dragged from button to header file to create an IBAction and set the value to touchUpInside. Here is what is happening:
http://screencast.com/t/R1WTpK7xp
WTF?
It triggers event when up is outside the button?
EDIT:
Here is the screenshot:
And what is the thing with down vote? I don't see a point in that.
View.h
#import <UIKit/UIKit.h>
#import "DrawingViewDelegate.h"
#interface DrawingBottomToolbarView : UIView
#property (weak) id <DrawingViewDelegate> delegate;
- (IBAction)lineSegmentButtonPush:(id)sender;
#end
View.m
#import "DrawingBottomToolbarView.h"
#implementation DrawingBottomToolbarView
#synthesize delegate;
- (id)initWithFrame:(CGRect)frame
{
NSLog(#"frame");
self = [super initWithFrame:frame];
if (self) {
// Initialization code
[self addSubview:[[[NSBundle mainBundle] loadNibNamed:#"DrawingBottomToolbarView" owner:self options:nil] objectAtIndex:0]];
//[[[NSBundle mainBundle] loadNibNamed:#"DrawingBottomToolbarView" owner:self options:nil] objectAtIndex:0];
//[self addSubview:self.];
}
return self;
}
//-(id)initWithCoder:(NSCoder *)aDecoder{
//
// NSLog(#"coder");
// if ((self = [super initWithCoder:aDecoder])){
// [self addSubview:[[[NSBundle mainBundle] loadNibNamed:#"DrawingBottomToolbarView" owner:self options:nil] objectAtIndex:0]];
// }
// return self;
//}
- (IBAction)lineSegmentButtonPush:(id)sender
{
NSLog(#"line push");
}
#end
I don't get it where is the problem.
EDIT 2:
I tried setting buttons as outlets and add target/action in code and same thing happens:
.h
#property (weak, nonatomic) IBOutlet UIButton *lineSegmentButton;
.m
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
[self addSubview:[[[NSBundle mainBundle] loadNibNamed:#"DrawingBottomToolbarView" owner:self options:nil] objectAtIndex:0]];
self.currentSelectedPathSegment = NoneSegment;
[self.lineSegmentButton addTarget:self action:#selector(lineSegmentButtonPush:) forControlEvents:UIControlEventTouchUpInside];
}
return self;
}
EDIT 3: Here is where I add two views. drawing view is created in code, bottomToolbar is created from .xib file.
kBottomToolbarHeight is constant with same value as height defined in .xib file.
- (void)viewWillAppear:(BOOL)animated
{
[self.view addSubview:self.drawingView];
[self.view addSubview:self.bottomToolbar];
CGRect selfRect = self.view.bounds;
CGRect drawingViewRect = selfRect;
CGRect bottomToobarRect = selfRect;
drawingViewRect.size.height = selfRect.size.height - kBottomToolbarHeight;
bottomToobarRect.size.height = kBottomToolbarHeight;
bottomToobarRect.origin.y = drawingViewRect.size.height;
self.drawingView.frame = drawingViewRect;
self.bottomToolbar.frame = bottomToobarRect;
}
The behavior you mention and show in the screencast is exactly the same as I experienced when I somewhere in the view hierarchy had a parent view with a UITapGestureRecognizer.
I'm unsure whether or not to flag your question as a possible duplicate of this one which helped me solve my problem.
For reference this is not a problem in iOS 6.0, only earlier versions.
I want to position a view (red box with label and button) prepared in IB as Subview on the screen programmatically. The positioning works fine with the "blue lines" (there might actually be a better way to simply draw a line on a view?!). But the view of the "AttributeApertureView" view object sticks to the top instead of following the initFrame Parameter starting at y=60 as you can see in the screenshot.
//Add blue Line
CGRect lineB = CGRectMake(0, 48, bounds.size.width, 0.5);
UIView *secondLine = [[UIView alloc]initWithFrame:lineB];
[secondLine setBackgroundColor:[UIColor colorWithRed:0.396 green:0.796 blue:0.894 alpha:1]];
[[self view]addSubview:secondLine];
//Add Attribute Aperture
AttributeApertureView *aperture = [[AttributeApertureView alloc]initWithFrame:CGRectMake(0, 60, bounds.size.width, 50)];
[aperture setBackgroundColor:[UIColor redColor]];
[[self view]addSubview:aperture];
Init function in AttributeApertureView class. This should basically only load the related nib file with the IB Interface.
#implementation AttributeApertureView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
NSArray *nib = [[NSBundle mainBundle]loadNibNamed:#"AttributeApertureView"
owner:self
options:nil];
self = [nib objectAtIndex:0];
}
return self;
}
What is the best way to position the "aperture" view on the screen?
Seems like calling loadNibNamed: resets the view's frame to what it is in the nib. This should work:
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
NSArray *nib = [[NSBundle mainBundle]loadNibNamed:#"AttributeApertureView"
owner:self
options:nil];
self = [nib objectAtIndex:0];
self.frame = frame;
}
return self;
}
because self = [super initWithFrame:frame]; sets the frame once, but self = [nib objectAtIndex:0]; ends up changing it again because you are resetting the whole view, so you have to set the frame again to be the one in the argument.