I have very simple UIView that creating the box, but what is happen is the UIView does not show at all, here is my code on sharingButtons.m
-(void)createContainer{
winWidth = [UIScreen mainScreen].bounds.size.width;
buttonContainer = [[UIView alloc] initWithFrame:CGRectMake(0, 0, winWidth, 20)];
buttonContainer.backgroundColor = [UIColor redColor];
[self.view addSubview:buttonContainer];
}
-(void)createButton{
[self createContainer];
}
and here is my sharingButtons.h
#interface SocialSharing : UIViewController {
int winWidth;
}
- (void)createButton;
- (void)createContainer;
#pragma mark - Properties
#property(nonatomic, strong) UIView* buttonContainer;
#end
And createButton method is called from MyViewControler.m on viewDidLoad
Is any wrong with my code??
EDITED
Here is my code on MyViewControler.m
- (void)loadSocialSharingButton {
socialButtons = [[SocialSharing alloc] init];
[socialButtons createButton];
}
- (void)viewDidLoad {
[super viewDidLoad];
[self loadSocialSharingButton];
}
Sorry I just learn about obj c :)
Thanks a lot
The reason your buttonContainer is not visible is, it is not loaded in your view hierarchy.
To make it visible you should add it as subview. In MyViewController.m in viewDidLoad add the following line after [self loadSocialSharingButton];
[self.view addSubview:socialButtons.buttonContainer];
Hope this Helps!
Your SocialSharing is subclass of UIViewController.
And you add your buttonContainer view to this SocialSharing Controller,this controller is not on screen if you just call
socialButtons = [[SocialSharing alloc] init];
[socialButtons createButton];
So,you can not see anything.
In an iOS App, only one ViewController at a time is active. And as you are at MyViewController, so MyViewController is active, if you want to navigate to any other view controller than you need to present or push the instance of same. Doing so will make the other view controller as active.
In your case the problem is your SocialSharing is a subclass of UIViewController as it is created as SocialSharing : UIViewController and it's not active, so adding any view over it won't be visible as the instance of SocialSharing is not pushed/ presented. If you need to show the view from SocialSharing than either you subclass it from UIView or push/ present the instance of SocialSharing to make it's view active and visible.
You are currently # MyViewController and But you are loading your custom view # SocialSharing ViewController, Both ViewController are distinct and you can't just get your custom view at social sharing to MyViewController by initializing it.
You have change SocialSharing class as sub class of UIView and initialize this view and add to subview of MyViewController.
SocialSharing.h
#interface SocialSharing : UIView {
int winWidth;
}
- (instancetype)createButton;
#pragma mark - Properties
#property(nonatomic, strong) UIView* buttonContainer;
#end
SocialSharing.m
- (instancetype)createButton
{
winWidth = [UIScreen mainScreen].bounds.size.width;
self = [super initWithFrame:CGRectMake(0, 0, winWidth, 20)];
if (self) {
buttonContainer = [[UIView alloc] initWithFrame:];
buttonContainer.backgroundColor = [UIColor redColor];
[self addSubview:buttonContainer];
}
return self;
}
MyViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
[self loadSocialSharingButton];
}
- (void)loadSocialSharingButton {
socialButtons = [SocialSharing alloc] createButton];
[self.view addSubView:socialButtons];
}
Related
I created a subclass of a UICollectionViewController that is used as the custom inputAccessoryViewController in a UITextView.
https://developer.apple.com/reference/uikit/uiresponder/1621124-inputaccessoryviewcontroller
I want to play the keyboard click sound when you tap a cell in the collection view using playInputClick.
https://developer.apple.com/reference/uikit/uidevice/1620050-playinputclick
I cannot figure out how to get this to work in a collection view. It works for a simple view like this using the inputAccessoryView property of a UITextView but I'm not sure what view to subclass in the collection view controller hierarchy to get the keyboard click sound to play.
#interface KeyboardClickView : UIView <UIInputViewAudioFeedback>
#end
#implementation KeyboardClickView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if(self)
{
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tap:)];
[self addGestureRecognizer:tap];
}
return self;
}
- (void)tap:(id)sender
{
[[UIDevice currentDevice] playInputClick];
}
- (BOOL)enableInputClicksWhenVisible
{
return YES;
}
#end
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
_inputAccessoryView = [[KeyboardClickView alloc] initWithFrame:CGRectMake(0, 0, 0, 50)];
_inputAccessoryView.backgroundColor = [UIColor redColor];
[[UITextView appearance] setInputAccessoryView:_inputAccessoryView];
// ...
}
#end
I'm also aware that you can play the keyboard click sound using AudioServicesPlaySystemSound(1104) but this doesn't respect the user's settings if they have the keyboard click sounds disabled.
To use the benefits of playInputClick in UIViewController:
Dummy input accessory view:
#interface Clicker : UIView <UIInputViewAudioFeedback>
#end
#implementation Clicker
- (BOOL)enableInputClicksWhenVisible
{
return YES;
}
#end
View with input accessory view:
#interface ControllerView : UIView
#end
#implementation ControllerView
- (BOOL)canBecomeFirstResponder
{
return YES;
}
- (UIView *)inputAccessoryView
{
return [[Clicker alloc] init];
}
#end
View Controller with custom view:
#implementation ViewController
- (void)loadView
{
self.view = [[ControllerView alloc] init];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self.view becomeFirstResponder];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[self.view resignFirstResponder];
}
#end
When the responder object becomes the first responder and inputView
(or inputAccessoryView) is not nil, UIKit animates the input view into
place below the parent view (or attaches the input accessory view to
the top of the input view).
There is no visual consequences since the height of Clicker view is zero, and conforming to UIInputViewAudioFeedback protocol enables [[UIDevice currentDevice] playInputClick] functionality within ViewController.
Look here for responder chains and here for input accessory views.
Instead of using a UICollectionViewController, define KeyboardClickView as a subclass of UICollectionView and place it on a UIViewController.
#interface KeyboardClickView : UICollectionView <UIInputViewAudioFeedback>
- (id)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout {
self = [super initWithFrame:frame collectionViewLayout:layout];
// existing implementation
The new view controller could look something like this:
#interface KeyboardClickViewController: UIViewController <UICollectionViewDelegate, UICollectionViewDataSource>
#property (nonatomic, strong) KeyboardClickView *clickView;
#end
#implementation KeyboardClickViewController
-(void)viewDidLoad {
[super viewDidLoad];
self.clickView = [[KeyboardClickView alloc] initWithFrame:self.view.bounds collectionViewLayout:[UICollectionViewFlowLayout new]];
self.clickView.delegate = self;
self.clickView.dataSource = self;
[self.view addSubview:self.clickView];
}
// existing UICollectionViewController logic
#end
This allows you to make the call to playInputClick from a UIView instead of a UIViewController.
Here's a working Swift 4.2 (iOS 11 and 12) version of bteapot's answer.
private class ClickerDummyView: UIView, UIInputViewAudioFeedback {
var enableInputClicksWhenVisible: Bool { return true }
}
private class ClickerControllerView: UIView {
override var canBecomeFirstResponder: Bool {
return true
}
override var inputAccessoryView: UIView? {
return ClickerDummyView()
}
}
class ClickingViewController: UIViewController {
override func loadView() {
self.view = ClickerControllerView()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
view.becomeFirstResponder()
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
view.resignFirstResponder()
}
}
Now call UIDevice.current.playInputClick() from within the ClickingViewController class whenever needed and the keyboard click sound will be triggered (with respect to system settings).
I am creating UIViewController programmatically. In its viewDidLoad, I am creating instance of custom UIView Component which has bunch of button and text filed. I set this view as viewControllers view.
But when I select any UIButton it does not fire any event or tapping inside UITextFiled does not bring up keyboard either.
- (void)viewDidLoad
{
[super viewDidLoad];
SomeView *sv = [[SomeView alloc] initWithFrame:self.view.bounds];
self.view.userInteractionEnabled = YES;
self.view = sv;
//[self.view addSubView:sv];
self.title = #"Something";
}
Is there anything wrong with this piece of code ? Even adding subivew does not work.
I added tapgesture to sv and It was getting detected but nothing else was getting selected on view.
I tried added buttons/textfiled to the viewcontrollers view directly. Then it works but not through customview component.
Try holding a strong reference to the view, It might be getting deallocated.
#interface YOURCLASS ()
#property (nonatomic, strong) SomeView *sv;
#end
And then Go back fro trying to add it as a subview. See if that works.
- (void)viewDidLoad
{
[super viewDidLoad];
self.sv = [[SomeView alloc] initWithFrame:self.view.bounds];
self.view.userInteractionEnabled = YES;
[self.view addSubView:self.sv];
self.title = #"Something";
}
I need a ViewController to be called modally to show some UIButton and other UIView on top of the current window. I want the background to be partially transparent and showing the current window below it - something similar to a UIActionSheet but with a custom design. I coded my VC to do the following: 1) during init the VC sets self.view.frame equals to [[UIApplication sharedApplication]keyWindow].frame 2) when show() is called the VC adds self.view on top of [[UIApplication sharedApplication]keyWindow] subViews 3) when an internal button calls the private method release() the VC remove self.view from its superview. Example with a single release button as follows:
#implementation ModalController
- (id)init
{
self = [super init];
if (self){
//set my view frame equal to the keyWindow frame
self.view.frame = [[UIApplication sharedApplication]keyWindow].frame;
self.view.backgroundColor = [UIColor colorWithWhite:0.3f alpha:0.5f];
//create a button to release the current VC with the size of the entire view
UIButton *releaseMyselfButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[releaseMyselfButton setTitle:#"Release" forState:UIControlStateNormal];
releaseMyselfButton.frame = CGRectMake(0, 0, 90, 20);
[releaseMyselfButton addTarget:self action:#selector(releaseMyself) forControlEvents:UIControlEventTouchDown];
//add the button to the view
[self.view addSubview:releaseMyself];
}
return self;
}
- (void) show
{
//add self.view to the keyWindow to make sure that it will appear on top of everything else
[[[UIApplication sharedApplication]keyWindow] addSubview:self.view];
}
- (void)releaseMyself
{
[self.view removeFromSuperview];
}
#end
If I create an instance of ModalController from another VC and I call show() everything goes as expected:
#interface CurrentVC ()
#property (strong, nonatomic) ModalController *myModalController;
#end
#implementation CurrentVC
- (void)viewDidLoad
{
[super viewDidLoad];
self.myModalController = [[ModalController alloc]init];
[self.myModalController show];
}
#end
To make it work I need to retain the ModalController in a property until release () is called. However I would like to have the same freedom I have with UIActionSheet and simply keep an instance of it in a local variable:
#implementation CurrentVC
- (void)viewDidLoad
{
[super viewDidLoad];
ModalController *myModalController = [[ModalController alloc]init];
[myModalController show];
}
#end
If I do this with the current code ARC will release myModalController straight after show() is called and the release button will be pointing to nil. How can I make this work without storing the object in a property? I've identified a work around but I'm not sure it's a good design option:
#interface ModalController ()
#property (strong, nonatomic) ModalController *myselfToAutorelease;
#implementation ModalController
- (id)init
{
self = [super init];
if (self){
... ... ...
self.myselfToAutorelease = self;
}
return self;
}
- (void) show
{
... ... ...
}
- (void)releaseMyself
{
[self.view removeFromSuperview];
self.myselfToAutorelease = nil;
}
What I've done is making ModalController "self sufficient" - it stores a pointer to itself during init and set it to nil when it's ready to release himself. It works but I have the feeling that this is against the ARC design principles! Is this approach correct? If not, how can I handle this differently?
Thanks in advance for your help.
Doesn't work like that.
You don't keep a reference to self.
In the main view controller you just create your object. If you need it to be around longer keep it in a property in the main view controller , when done, set the property to nil in the main view controller.
This may sound like a simple question, but yet I can't find an answer for it anywhere.
I am switching between views and everything is fine. I can pass variables and data between views, but the problem arises when I want to go back to a previous view.
Any data on the view is gone and deleted as if it hadn't been passed through. Of course, I don't want the data to unload when I switch to a new view. Is this possible?
This is how I am switching between views in my project. Is there a better way?
TicketStart *backPage=[[TicketStart alloc]initWithNibName:#"TicketStart" bundle:nil];
[self addChildViewController:backPage];
[self.view addSubview:backPage.view];
When I search this question all I can find are questions about passing things through or loading new views. Sorry if this question has been asked, but I can not find an answer anywhere.
I'm not sure what triggers your views to change, so you'll have to write that code.
Parent
#implementation ParentViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
self.vcOne = [[OneViewController alloc] init];
[self addChildViewController:self.vcOne];
[self.view addSubView:self.vcOne.view];
self.vcTwo = [[TwoViewController alloc] init];
}
-(void)switchViews {
//logic to animate in view that isn't present
}
#end
View Controller One
#interface OneViewController ()
#property(strong, nonatomic) UIView *vOne;
#end
#implementation OneViewController
-(UIView*)vOne {
if(_vOne == nil) {
_vOne = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, self.view.frame.size.width, self.view.frame.size.height)];
}
return _vOne;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
[self.view addSubView:self.vOne];
}
#end
View Controller Two
#interface TwoViewController ()
#property(strong, nonatomic) UIView *vTwo;
#end
#implementation TwoViewController
-(UIView*)vTwo {
if(_vTwo == nil) {
_vTwo = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, self.view.frame.size.width, self.view.frame.size.height)];
}
return _vTwo;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
[self.view addSubView:self.vTwo];
}
#end
I'm trying to use a Button in my UIPopover to create a UITextView in my Main UIViewController the code I have looks something like this (PopoverView.h file):
#protocol PopoverDelegate <NSObject>
- (void)buttonAPressed;
#end
#interface PopoverView : UIViewController <UITextViewDelegate> { //<UITextViewDelegate>
id <PopoverDelegate> delegate;
BOOL sendDelegateMessages;
}
#property (nonatomic, retain) id delegate;
#property (nonatomic) BOOL sendDelegateMessages;
#end
Then in my PopoverView.m file:
- (void)viewDidLoad
{
[super viewDidLoad];
UIButton * addTB1 = [UIButton buttonWithType:UIButtonTypeRoundedRect];
addTB1.frame = CGRectMake(0, 0, 100, 50);
[addTB1 setTitle:#"Textbox One" forState:UIControlStateNormal];
[self.view addSubview:addTB1]; // Do any additional setup after loading the view from its nib.
[addTB1 addTarget:self action:#selector(buttonAPressed)
forControlEvents:UIControlEventTouchUpInside];
}
- (void)buttonAPressed
{
NSLog(#"tapped button one");
if (sendDelegateMessages)
[delegate buttonAPressed];
}
And also in my MainViewController.m :
- (void)buttonAPressed {
NSLog(#"Button Pressed");
UITextView *textfield = [[UITextView alloc] init];
textfield.frame = CGRectMake(50, 30, 100, 100);
textfield.backgroundColor = [UIColor blueColor];
[self.view addSubview:textfield];
}
I'm using a delegate protocol to link the popover and the ViewController but I'm stuck on how I get my BOOL statement to link the -(void)buttonAPressed in the PopoverView and MainViewController so that when I press the button in the Popover a textview appears in the Main VC. How would I go about doing this?
In MainViewController, where you create PopoverView, be sure to set its delegate property otherwise sending messages to delegate in PopoverView will do nothing.
For example, in MainViewController.m:
PopoverView *pov = [[PopoverView alloc] initWithNibName:nil bundle:nil];
pov.delegate = self; // <-- must set this
thePopoverController = [[UIPopoverController alloc] initWithContent...
I am not sure why you need the sendDelegateMessages variable. Even with that bool, you must set the delegate property so PopoverView has an actual object reference to send the messages to.
If you want to make sure the delegate object has implemented the method you're about to call, you can do this instead:
if ([delegate respondsToSelector:#selector(buttonAPressed)])
[delegate buttonAPressed];
Also, the delegate property should be declared using assign (or weak if using ARC) instead of retain (see Why use weak pointer for delegation? for an explanation):
#property (nonatomic, assign) id<PopoverDelegate> delegate;
Another thing is if you're not using ARC, you need to add [textfield release]; at the end of the buttonAPressed method in MainViewController to avoid a memory leak.