I want to add my custom UIView to my main view.
I want to use the function initWithTitle:description: like:
AchievementView *achievement = [[AchievementView alloc] initWithTitle:#"Test" description:#"The Descr"]];
But this doesn't work. tThe initWithTitle:description: function have to be implemented as class method.
AchievementView.h
#interface AchievementView : UIView
#property (strong) NSString *achievementTtl;
#property (strong) NSString *achievementDescr;
#property (strong) UIView *theAchievementView;
- (void)initWithTitle:(NSString*)achievementTitle description:(NSString*)achievementDescription;
- (void)showAchievement;
#end
AchievementView.m
-(void)initWithTitle:(NSString*)achievementTitle description:(NSString*)achievementDescription {
self.achievementTtl = achievementTitle;
self.achievementDescr = achievementDescription;
}
- (void)showAchievement {
// Create view popup
self.theAchievementView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 300, 423)];
self.theAchievementView.layer.cornerRadius = 8;
self.theAchievementView.layer.masksToBounds = YES;
self.theAchievementView.layer.shadowRadius = 5;
self.theAchievementView.layer.shadowOpacity = .15;
[self.theAchievementView setBackgroundColor:[UIColor whiteColor]];
[self addSubview:self.theAchievementView];
}
Call the method in main view:
- (IBAction)share:(id)sender {
AchievementView *achievement = [[AchievementView alloc] init];
achievement.achievementTtl = #"Test";
achievement.achievementDescr = #"TestDEscr";
[achievement showAchievement];
}
I can't add the subview to the main view with this function.
I think the "self" is wrong. What should be there?
[self addSubview:self.theAchievementView];
You have 2 questions: how to initialize the view and how to add it to the screen.
You can use the initWithTitle:description: method, you just have to use it on an instance of the class, not the class itself:
[[AchievementView alloc] initWithTitle:#"Test" description:#"The Descr"]];
You are correct that you have the wrong self in your addSubview call. You need a reference to the parent view. You could pass it into your AchievementView class, but it is cleaner to manage that outside of the class.
I also noticed that AchievementView is a subclass of UIView, but you are creating another UIView inside it. It would be simpler to directly use the AchievementView. Your code should be similar to the below:
AchievementView.h
#interface AchievementView : UIView
#property (strong) NSString *achievementTtl;
#property (strong) NSString *achievementDescr;
- (id)initWithTitle:(NSString*)achievementTitle description:(NSString*)achievementDescription;
#end
AchievementView.m
- (id)initWithTitle:(NSString*)achievementTitle description:(NSString*)achievementDescription {
if (self = [super initWithFrame:CGRectMake(0, 0, 300, 423)]) {
self.achievementTtl = achievementTitle;
self.achievementDescr = achievementDescription;
self.layer.cornerRadius = 8;
self.layer.masksToBounds = YES;
self.layer.shadowRadius = 5;
self.layer.shadowOpacity = .15;
self.backgroundColor = [UIColor whiteColor];
}
return self;
}
Main view
- (IBAction)share:(id)sender {
AchievementView *achievement = [[AchievementView alloc] initWithTitle:#"Test" description:#"TestDEscr"];
[self.view addSubview:achievement];
}
Number one, you are never adding achievement as a subview of your main view. Basically you are creating a view offscreen, adding a view to that view, then moving on with whatever you want to do without ever moving the first view onto the screen.
As a minimum you should do this:
- (IBAction)share:(id)sender {
AchievementView *achievement = [[AchievementView alloc] init];
achievement.achievementTtl = #"Test";
achievement.achievementDescr = #"TestDEscr";
[achievement showAchievement];
[self addSubview:achievement];
}
Along with setting the frame size of achievement which is currently never set (and since most views by default mask to their layer bounds it will mask to (0,0,0,0)).
Then I would seriously reconsider how you are dealing with views and subviews. If you do things properly, your initwithtitle will work just fine.
Related
In my application, I do not use the NavigationController, in general.
In UITableView I would do so, would add
[Self.view addSubview: self.myCustomHeaderView];
But I'm using ASTableNode. If I do something, something similar here:
- (instancetype)init {
_tableNode = [[ASTableNode alloc] init];
self = [super initWithNode:_tableNode];
if (self) {
_tableNode.dataSource = self;
_tableNode.delegate = self;
self.navigationItem = //navigationItem implement
UINavigationBar *navbar = [[UINavigationBar alloc]initWithFrame:CGRectMake(0, 0, 320, 50)];
navbar.backgroundColor = [UIColor redColor];
navbar.items = #[self.navigationItem];
ASDisplayNode *navBarNode = [[ASDisplayNode alloc] initWithViewBlock:^UIView * _Nonnull {
return navbar;
}];
[self.node addSubnode:navBarNode];
}
return self;
}
Then this node is added as part of the list and scrolled along with the list, and I need it to be as fixed header.
initWith ASDisplayNode rather than ASTableNode,then add table node on VC's node,for example:
#interface OCTextureTableController : ASViewController<ASDisplayNode *>
#property (nonatomic, strong) ASTableNode *tableNode;
- (instancetype)init
{
self = [super initWithNode:[ASDisplayNode new]];
if (self) {
self.tableNode = [[ASTableNode alloc] init];
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.tableNode.backgroundColor = [UIColor yellowColor];
self.tableNode.frame = CGRectMake(0, NAVIGATION_BAR_HEIGHT, SCREEN_WIDTH, SCREEN_HEIGHT-NAVIGATION_BAR_HEIGHT);
[self.node addSubnode:self.tableNode];
}
(i) take Class A as base Class.
(ii) take Class B as derived Class having type of class A.
Now in class A Add a uiview on top. that will be considered as navigation.(do anything in that view)
To use same navigation bar: you have to take other all classes as having type of class A.
that's it.
In Swift I would do this to create a UIView in a kind of closure (I think this is a closure), how can I do this same exact thing in objective-C?
I don't want to set up all the variables and stuff like that in ViewDidLoad().
Thanks for your help.
let myView: UIView = {
let view = UIView()
view.layer.masksToBounds = true
view.layer.cornerRadius = 5
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
The closest you can get without doing it in init or viewDidLoad is lazy instantiation.
#interface SomeClass: NSObject
#property (nonatomic, strong) UIView *myView;
#end
#implementation SomeClass
- (UIView *)myView
{
if (!_myView) {
_myView = [[UIView alloc] init];
_myView.layer.masksToBounds = YES;
_myView.layer.cornerRadius = 5;
_myView.translatesAutoresizingMaskIntoConstraints = NO;
}
return _myView;
}
#end
You can create nearly identical code in Objective-C:
- (void)viewDidLoad {
[super viewDidLoad];
UIView *myView = ^UIView*() {
UIView *view = [[UIView alloc] initWithFrame: CGRectZero];
view.layer.masksToBounds = TRUE;
view.layer.cornerRadius = 5;
view.translatesAutoresizingMaskIntoConstraints = FALSE;
//Add constraints
return view;
}();
[self.view addSubview: myView];
}
However, that won't create a computed variable like it does in Swift. It just defines a block and calls it in order to initialize a local variable.
I have a GameOver UIView that I call from inside my main UIViewController. It is just a 'popover' window that has the text game over, the score, and some blur effects to blur the main UIViewcontroller.
I try to pass an int to the UIView, but it doesn't accept it unless it is in the - (void)drawRect:(CGRect)rect method.
If I move the score label to drawRect method, the label is updated. But the blur effects go away.
What am I doing wrong?
MainViewController.m
#import "GameOverView.h"
#interface ViewController () {
GameOverView * gov;
}
- (void) showGameOver {
gov = [[GameOverView alloc] initWithFrame:self.view.bounds];
NSLog(#"Passing score of: %i", self.score);
gov.finalScore = self.score;
[self.view addSubview:gov];
}
GameOverView.h
#interface GameOverView : UIView {}
#property (nonatomic) int finalScore;
#end
GameOverView.M
#implementation GameOverView
- (id) initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
// Initialization code
//self.backgroundColor = [UIColor redColor];
NSLog(#"Score:%i", self.finalScore );
UIVisualEffect *blurEffect;
blurEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];
UIVisualEffectView *visualEffectView;
visualEffectView = [[UIVisualEffectView alloc] initWithEffect:blurEffect];
visualEffectView.frame = super.bounds;
[super addSubview:visualEffectView];
UILabel * lblGameOver = [[UILabel alloc] initWithFrame:CGRectMake(0,0, frame.size.width, 200)];
lblGameOver.center = CGPointMake(frame.size.width/2, 100);
lblGameOver.text = [NSString stringWithFormat: #"GAME OVER %i", self.finalScore];
[self addSubview:lblGameOver];
UIButton * button = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, frame.size.width, 200)];
button.center = CGPointMake(frame.size.width/2, 200);
[button setTitle:#"Start New Game" forState:UIControlStateNormal];
[button addTarget:self action:#selector(removeSelfFromSuperview) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:button];
}
return self;
}
- (void) removeSelfFromSuperview{
[self removeFromSuperview];
}
You are using the finalScore property in the init method of the GameOverView class, but you are only setting its value after initializing it.
Change your initialization method to
- (id) initWithFrame:(CGRect)frame finalScore:(int)fs{
// use 'fs' instead of 'self.finalScore'
}
It should work.
I wonder how there isn't any problem with the view background color. You are initializing the view and adding it as subview like this:
gov = [[GameOverView alloc] initWithFrame:self.view.bounds];
gov.finalScore = self.score;
[self.view addSubview:gov];
This will give the view background color as black which is default color. So you don't find much difference if you use blur effect.
you need to give the color for the view during the initialization :
gov = [[GameOverView alloc] initWithFrame:self.view.bounds];
[gov setBackgroundColor:[UIColor yourColor]];
[self.view addSubview:gov];
If you are planning to keep the code in initWithFrame, you don't need to worry about setting the background color. If you keep the code in drawRect, then you must set the background color,else it will be black color.
When coming to setting the score label, it doesn't matter whether you put it in drawRect or initWithFrame method. Make sure you use drawRect method only if you really have to draw on the view,so that you can call it later by using setNeedsDisplay
I need a little help about my code. I want to create a custom bar graph. I did all the coding. When I create the objects in my custom class view it works like a charm. However, I want to make it generic. I would like to create it in ViewController. I also add a view in storyboard and change the class name to my custom class name.
It doesn't work when I try like this.
#implementation ViewController
-(void)viewDidLoad {
[super viewDidLoad];
GCBarGraphRow *first = [[GCBarGraphRow alloc]init];
first.backgroundColor = [UIColor redColor];
first.value = 20;
GCBarGraphRow *second = [[GCBarGraphRow alloc]init];
second.backgroundColor = [UIColor brownColor];
second.value = 40;
GCBarGraphColumn *container = [[GCBarGraphColumn alloc]init];
container.values = #[first,second];
NSLog(#"View Controller %#",container.values);
self.myGraph.array = container;
}
But when I try to create it in my custom view class it works.
#implementation GCBarGraphView
-(id)initWithCoder:(NSCoder *)aDecoder {
if ((self = [super initWithCoder:aDecoder])) {
barNumber = [array.values count];
//NSLog(#"%#",array.values);
showDifference = NO;
showShadow = NO;
gradientColor = NO;
drawBaseLine = YES;
[self baseClassInit];
}
return self;
}
-(void)baseClassInit {
GCBarGraphRow *first = [[GCBarGraphRow alloc]init];
first.backgroundColor = [UIColor redColor];
first.value = 20;
GCBarGraphRow *second = [[GCBarGraphRow alloc]init];
second.backgroundColor = [UIColor brownColor];
second.value = 40;
GCBarGraphColumn *container = [[GCBarGraphColumn alloc]init];
container.values = #[first,second];
}
If you're creating a view in the storyboard and assign it's class to your CGBarGraphRow, you also need to create an outlet to your view controller.
Then you don't have to initialize it manually from the view controller code. Your constructor initWithCoder will be called automatically.
Update:
Try this. In the storyboard create the following:
- UIView with proper frame and assign custom class to CGBarGraphView
- Insert into that view two more and assign their classes to GCBarGraphRow
In your CGBarGraphView class create two outlets and bind them to the proper views in the storyboard:
#property (nonatomic, weak) IBOutlet GCBarGraphRow *row1;
#property (nonatomic, weak) IBOutlet GCBarGraphRow *row2;
Remove the code you have above for the view controller - it's not needed. Leave something like that in the CGBarGraphView code:
-(id)initWithCoder:(NSCoder *)aDecoder {
if ((self = [super initWithCoder:aDecoder])) {
}
return self;
}
-(void)viewDidLoad {
GCBarGraphColumn *container = [[GCBarGraphColumn alloc]init];
container.values = #[self.row1,self.row2];
... whatever else you need to initialize
}
How to create a simple scroll view when clicking a button in Xcode?
I have assigned the button and gave IBAction as press,
what to code to make a scroll view on this action?
-(IBAction)press
{
}
In .h file you must add delegate definition to your class declaration - something like this:
#interface someClass : NSObject <UIScrollViewDelegate>
In .m write somethink like this:
-(IBAction)press
{
UIScrollView *_scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height)];
_scrollView.backgroundColor = [UIColor clearColor];
_scrollView.userInteractionEnabled = YES;
_scrollView.delegate = nil;
[self.view addSubview:self.scrollView];
}
That's all! :)