Changing from UIView to UIView in another class - objective-c

Here is a small problem I am having. I am not too good at programmatically changing views, but this is what I have:
//(.h)
#import <UIKit/UIKit.h>
#import "Detail.h"
#interface List : UIViewController <UITableViewDelegate, UITableViewDataSource>
{
}
#property (retain, nonatomic) IBOutlet UITableView *tableView;
#property (retain, nonatomic) Detail *detail;
#end
and
//(.m)
#synthesize detail=_detail;
- (Detail *)detail
{
NSLog(#"Detail UIView construction started.");
if (_detail != nil)
{
return _detail;
}
Detail *aDetailView = [[Detail alloc] init];
_detail = aDetailView;
[self.view addSubview:_detail.view];
//I never really set it to setHidden:YES, but just to make sure I'm setting it NO here.
[_detail.view setHidden:NO];
return _detail;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[UIView transitionFromView:self.view toView:self.detail.view duration:1 options:UIViewAnimationOptionTransitionFlipFromRight completion:nil];
}
As output:
2012-02-07 11:17:51.909 TodoApp[4232:fb03] Detail UIView construction started.
The view seems to do the FlipFromRight animation fine, but the screen is totally black.
As I said, I'm not good at changing views programmatically.
Thanks for any help!
=============
Answering my own question.
It was really stupid. The "Back" button in the Title bar had an unsupported configuration. So the View did not want to load... fixed it now.

- (Detail *)detail
{
NSLog(#"Detail UIView construction started.");
if (_detail != nil)
{
return _detail;
}
Detail *aDetailView = [[Detail alloc] init];
[self.view addSubview:aDetailView.view];
//I never really set it to setHidden:YES, but just to make sure I'm setting it NO here.
[aDetailView.view setHidden:NO];
_detail = aDetailView;
return _detail;
}
make these changes and let me know the result..

you are returning _detail before adding it to superview
so add this line
return _detail;
after this line [self.view addSubview:_detail.view];
like this
[self.view addSubview:_detail.view];
[_detail.view setHidden:NO];
return _detail;

Answering my own question.
It was really stupid. The "Back" button in the Title bar had an unsupported configuration. So the View did not want to load... fixed it now.

Related

scope button of UISearchBar does not work on IOS 13 when using UISearchDisplayController

I have to maintain a quite old and large objective-c project.
Every thing works fine until iOS12 but from iOS13 the scope-button-bar of UISearchBar does not work with UISearchDisplayController.
I know that UISearchDisplayController is deprecated but I really don't want to migrate it to UIDisplayController because of some reasons.
I did some test and find out the problem might related to UIDisplayController as it block the user touch on the scope button.
My code as below:
#implementation MyUISearchDisplayController
- (void)setActive:(BOOL)visible animated:(BOOL)animated
{
if(self.active == visible){ return; }
[self.searchContentsController.navigationController setNavigationBarHidden:YES animated:NO];
[super setActive:visible animated:animated];
[self.searchContentsController.navigationController setNavigationBarHidden:NO animated:NO];
if (visible)
{
[self.searchBar becomeFirstResponder];
}
else
{
[self.searchBar resignFirstResponder];
}
}
#end
#interface TopBarViewController ()
#property (strong, nonatomic) IBOutlet UISearchBar *searchBar;
#property (strong, nonatomic) UISearchDisplayController *searchController;
#end
#implementation TopBarViewController
- (void)viewDidLoad {
[super viewDidLoad];
//The default state for show-cancel-button and show-scope-bar of searchBar is false (not showing)
self.searchBar.scopeButtonTitles = #[#"scope1", #"scope2", #"scope3", #"scope4"];
self.searchController = [[MyUISearchDisplayController alloc] initWithSearchBar:self.searchBar contentsController:self];
self.searchController.delegate = self;
}
The code above works as well until IOS12, but from IOS13 I cannot touch the scope button. I guess the problem related to the UIDisplayController class.
So I'm thinking of overwrite some method of UIDisplayController but don't know how to start. Any body have experience with that. Any information would be appreciated. Thanks.
I'm quite new to Objective-C and IOS, I did a lot of search on google but no luck.
updated:
After some days debugging I solved my problem by overwriting the hitTest method of UISearchBar class. The following should do the trick (also it's not a documented way)
#implementation MyUISearchBar
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{
UIView * touchedView = [super hitTest:point withEvent:event];
if(check version stuff){
return touchedView;
}
UIView * scopeBar = [self performSelector:NSSelectorFromString(#"_scopeBar")];
if(user touched the scopeBar){
return scopeBar;
}
return touchedView;
}
Hope it helps some one.
UISearchDisplayController is deprecated, use UISearchController instead.
Look here
https://useyourloaf.com/blog/updating-to-the-ios-8-search-controller/
You must migrate because UISearchDisplayController will not work correctly in iOS13.
Look at this project, is good example how to manage UISearchController.
https://github.com/kharrison/CodeExamples/tree/master/WorldFacts
Good luck

How to clear the image in textField on the tap of textField,Objective C?

I have set the image to textFiled using rightmodeview on clicking button,
now what I want is, I want to hide the image on tapping the textField without touching button?
Help me out
Do something like:
-(void)textFieldDidBeginEditing:(UITextField *)textField {
textfield.rightView=nil;
//Do other stuff,if you want to do
}
I created sample one and I tried it works fine.
ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController<UITextFieldDelegate>
#property (strong, nonatomic) IBOutlet UITextField *txtFldImage;
#end
ViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
txtFldImage.rightViewMode = UITextFieldViewModeAlways;
txtFldImage.rightView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"boss-icon.png"]];
}
-(void)textFieldDidBeginEditing:(UITextField *)textField{
txtFldImage.rightView = nil;
}
When run the app
When I enter or touch the textField
this code is working for me
-(void)textFieldDidBeginEditing:(UITextField *)textField {
//set right view nil
}
and make sure you set delegate of UITextField for your textfield
Add below code in viewDidLoad
yourTextField.delegate = self;

Understanding delegation

I am trying to understand delegation. I have written a small project to try to tackle this. I have also had help from S.O. I am stuck on the very last part of it. My project is simple. We have a main view controller that has a button "start". This button triggers a container view that's hooked to a ContainerViewController. I have done a small animation to get the container to slide from the side. I have another button "back" that makes the container view disappear with the opposite animation. Note, I am copying a lot of code and making up the rest as I am learning, so there may be unnecessary lines, please feel free to comment.
ViewController.h
#import <UIKit/UIKit.h>
#import "ContainerViewController.h"
#interface ViewController : UIViewController <ContainerViewControllerDelegate>
- (IBAction)Start:(id)sender;
- (IBAction)back:(id)sender;
#end
Here is the m file:
#import "ViewController.h"
#interface ViewController ()
#property UIViewController *childView;
#property NSString *myReceivedValue;
#property ContainerViewController *controller;
#property IBOutlet UILabel *myLabel;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.childView = [self.storyboard instantiateViewControllerWithIdentifier:#"childVC"];
self.controller = [self.storyboard instantiateViewControllerWithIdentifier:#"childVC"];
self.controller.delegate = self;
self.childView = [self.childViewControllers lastObject];
[self.childView.view removeFromSuperview];
[self.childView removeFromParentViewController];
self.childView.view.userInteractionEnabled = NO;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)Start:(id)sender {
self.childView.view.frame = CGRectMake(0, 84, 320, 210);
[self.childView didMoveToParentViewController:self];
CATransition *transition = [CATransition animation];
transition.duration = 1;
transition.type = kCATransitionPush;
transition.subtype = kCATransitionFromLeft;
[transition setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
[self.childView.view.layer addAnimation:transition forKey:nil];
[self.view addSubview:self.childView.view];
self.childView.view.userInteractionEnabled = YES;
}
- (IBAction)back:(id)sender {
[self.childView willMoveToParentViewController:nil];
[UIView animateWithDuration:1
delay:0.0
usingSpringWithDamping:1
initialSpringVelocity:1
options:UIViewAnimationOptionCurveEaseIn
animations:^{
self.childView.view.frame = CGRectMake(-320, 84, 320, 210);
} completion:^(BOOL complete){
[self.childView removeFromParentViewController];
}];
}
- (void) passValue:(NSString *) theValue
{
// here is where you receive the data
}
#end
Ok, so the Container View has a pickerView of which it is the delegate and this pickerView has just an array of ten colors to chose from:
h file for the container view:
#import <UIKit/UIKit.h>
#protocol ContainerViewControllerDelegate;
#interface ContainerViewController : UIViewController <UIPickerViewDelegate>
#property NSArray *colors;
#property (weak)id <ContainerViewControllerDelegate> delegate;
#property (weak, nonatomic) IBOutlet UIPickerView *myPickerView;
- (IBAction)chosenCol:(id)sender;
#end
#protocol ContainerViewControllerDelegate <NSObject>
- (void) passValue:(NSString *) theValue;
#end
m file for the container view:
#import "ContainerViewController.h"
#interface ContainerViewController ()
#property NSString *selValue;
#end
#implementation ContainerViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.colors = [[NSArray alloc] initWithObjects:#"blue", #"red", #"green", #"purple", #"black", #"white", #"orange", #"yellow", #"pink", #"violet", nil];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView {
return 1;
}
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component {
return 10;
}
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component {
return self.colors[row];
}
- (IBAction)chosenCol:(id)sender {
[self.delegate passValue:[self.colors objectAtIndex:[self.myPickerView selectedRowInComponent:0]]];
}
#end
Here is a picture of what it looks like. Note that the "chosen" button is just a provisional one that I put there to make sure everything is hooked alright and that I can log out the chosen color using a button in the container. What I want to do is be able to pass that color to the parent view controller. So that after I dismiss the container with its picker view I have the data stored of what color was chosen. I have had help from someone in S.O. and he's done a very good job of helping me start this up. The only thing I didn't understand is what happens when I receive the data, at the end of the m file of the parent:
- (void) passValue:(NSString *) theValue
{
// here is where you receive the data
}
This is obvioulsy noob question but I really do need it spelt out. How do I actually access the data in the parent. I asked in the comments section, and the reply was (I am changing the class, it was originally uicolor):
"No, you'll receive the data inside the method - (void) passValue:(NSString *) theValue; Put a breakpoint in that method to be sure that it's working, you can access it like this: NSString *myReceivedColor = theValue;
I tried to write word for word "NSString *myReceivedColor = theValue;" but "theValue" is unrecognised.
Ultimately, what I want, is to pass the data back to the parent so that when I hit the button "back", in the parent, the label "you chose" is updated with the chosen color".
I have never touched delegation before so I am lost. Can a charitable soul take the time to explain this last bit in very obvious terms? many thanks
UPDATE-----------------------------------------------------------------------
So, what I am looking at, is to add, at the end of my method for the "back" button,
- (IBAction)back:(id)sender {
[self.childView willMoveToParentViewController:nil];
[UIView animateWithDuration:1
delay:0.0
usingSpringWithDamping:1
initialSpringVelocity:1
options:UIViewAnimationOptionCurveEaseIn
animations:^{
self.childView.view.frame = CGRectMake(-320, 84, 320, 210);
} completion:^(BOOL complete){
[self.childView removeFromParentViewController];
}];
the couple of lines:
self.myReceivedValue = theValue;
self.myLabel.text = self.myReceivedValue;
}
To be able to update the text of myLabel to the the color I've chosen in the view container. It comes back with the error: "use of undeclared identifier "theValue". This is all new to me so I am just copying what people have said on S.O. with the hope of understanding eventually. What am I doing wrong here? tx
It looks like your delegate is nil.
self.childView = [self.storyboard instantiateViewControllerWithIdentifier:#"childVC"];
self.controller = [self.storyboard instantiateViewControllerWithIdentifier:#"childVC"];
self.controller.delegate = self;
You create two instances of "childVC" (a copy/paste typo maybe?) then set the delegate on 'controller' but you use 'childView'. Just change the childView property to be a ContainerViewController and set self.childView.delegate=self.
(BTW its an easy mistake, so many times when you're thinking "why isn't this working??" check that the delegate property is set)
EDIT
The return value property you're logging is nil b/c you never set it. You have to implement the delegate method, i.e.
-(void) passValue:(nsstring*)theValue
{
self.receivedValue = theValue
}
Also what i was saying about the chosenCol action is that is where you are calling your delegate - your 'back' action does not call this method.

Making a UIButton change a UIImageView image

I'm very new to programming and objective c so please go easy on me.
I would like a UIButton (which I'm using as an IBAction) to change an the image in a UIImageView when pressed. I put the UIImageView into a UIScrollView in the storyboard but I hope I can still programmatically change the image.
I have searched absolutely everywhere for an answer for hours but nothing has worked for me either because it wasn't the right solution or I didn't do it properly.
I have tried this code and some more but they always return a "Thread 1: signal SIGABRT" when I press the button:
imageView.image = [UIImage imageNamed: #"Ruler pic inch.png"];
Here is my code so far:
ViewController.h
#import <UIKit/UIKit.h>
#import <iAd/iAd.h>
#interface ViewController : UIViewController <ADBannerViewDelegate, UIScrollViewDelegate> {
ADBannerView *adView;
BOOL bannerIsVisible;
IBOutlet UIScrollView *scrollView;
IBOutlet UIImageView *imageView;
IBOutlet UIButton *proVersion;
IBOutlet UIButton *howToUse;
}
- (IBAction)switchUnit:(id)sender;
#property (nonatomic, assign) BOOL bannerIsVisible;
#property (nonatomic, retain) IBOutlet UIScrollView *scrollView;
#property (nonatomic, retain) IBOutlet UIImageView *imageView;
#end
ViewController.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize bannerIsVisible;
#synthesize scrollView;
#synthesize imageView;
- (void)viewDidLoad
{
[super viewDidLoad];
// Hide status bar:
[[UIApplication sharedApplication] setStatusBarHidden:YES];
// iAd:
adView = [[ADBannerView alloc] initWithFrame:CGRectZero];
adView.frame = CGRectOffset(adView.frame, 0, -50.0f);
[self.view addSubview:adView];
adView.delegate=self;
self.bannerIsVisible=NO;
// Setting scrollview content size to size of image
scrollView.contentSize = CGSizeMake(320,2246);
}
-(void)bannerViewDidLoadAd:(ADBannerView *)banner
{
if (!self.bannerIsVisible) {
[UIView beginAnimations:#"animateAdBannerOn" context:NULL];
banner.frame = CGRectOffset(banner.frame, 0, 50.0f);
[UIView commitAnimations];
self.bannerIsVisible = YES;
}
}
-(void)bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError *)error
{
if (self.bannerIsVisible) {
[UIView beginAnimations:#"animateAdBannerOff" context:NULL];
banner.frame = CGRectOffset(banner.frame, 0, -50.0f);
[UIView commitAnimations];
self.bannerIsVisible = NO;
}
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)switchUnit:(id)sender {
// CODE THAT MAKES IMAGE CHANGE GOES HERE (I thought...)
}
#end
Help would be greatly appreciated. I'm fed up with it. I've probably done a silly mistake somewhere but I can't work it out. Thanks in advance.
General pointers:
Try to use #property for all your instance variables (it'll server you well in future)
Don't use #synthesize (the compiler does a better job of it for you)
If you have a property bob, access it by using self.bob
Turn on ARC (looks like you don't have it on currently)
Best not to have any spaces in image names
To be clear on properties, when you have a property you don't need to create instance variables in between {} of the #interface. These should be removed in order to prevent multiple definitions. The auto-synthesising done by the compiler will define the instance variables for you but you should always use the property to access the value (as in item 3 above).
That said, your - (IBAction)switchUnit:(id)sender looks fine, if a little empty. The code should be something like:
self.imageView.image = [UIImage imageNamed:#"Ruler_pic_inch.png"];
For it to work, the image Ruler_pic_inch.png would need to be in your bundle (which means it's in Xcode project and set to copy during the build.
Again, that said, your problem would seem to relate to you being confused somewhere. SIGABRT type issues would usually be picked up by the compiler and notified to you as a warning saying something like "some object may not respond to some selector". If you see any of those, look at them and work out why you're trying to ask the object a question it doesn't understand.
If you don't see any compiler warnings, then you've told the compiler that an object is going to be of one type and then actually set it to something else. In this case I'd look at your IBOutlets in Storyboard and check that they are actually set to the correct destination view (disconnect and reconnect them all to be sure).

Why isn't my UIButton responding to touches?

I'm sure I'm overlooking the obvious as I've got countless working buttons...but...for whatever reason this one is not cooperating...
I've added a UIButton (Rounded Rect) to a UIView subclass (DialogView) which is a subview of my view controller's view. This subview is created almost entirely in IB. I've wired up the button to (IBAction)okButtonPressed:(id)sender in IB to Touch Up Inside and created a corresponding method in DialogView. However when I "touch" this button it doesn't trigger the method. userInteractionEnabled is true for the VC's view, DialogView and the UIButton.
Thinking maybe initWithCoder had to do some frame manipulation or something I added the following which successfully logs to console.
- (id)initWithCoder:(NSCoder *)decoder {
if (self = [super initWithCoder:decoder]) {
NSLog(#"DialogView initWithCoder called");
}
return self;
}
In further exploration I wired up an IBOutlet to the button and then if I try to change the titleLabel from the view controller I notice that it get's severely truncated. Default text of say "Press Me!" set in IB displays fine when view is first drawn. But if I change the text...
self.DialogView.okButton.titleLabel.text = #"Not Working";
...it gets truncated to "N..."
Dunno if this is related. Probably...
Anyone see what I've screwed up here?
Edit (adding code related to showing UIButton):
From the View Controller:
self.DialogView = [[[NSBundle mainBundle] loadNibNamed:#"DialogView" owner:self options:nil] objectAtIndex:0];;
self.DialogView.myVC = self;
self.DialogView.backgroundColor = [UIColor clearColor];
self.DialogView.center = CGPointMake(self.view.frame.size.width / 2, self.view.frame.size.height / 2);
self.DialogView.nameLabel.text = loan.fullName;
self.DialogView.noteLabel.text = loan.summaryOfLoan;
self.DialogView.amountLabel.text = [currencyFormatter stringFromNumber:loan.originalAmount];
self.DialogView.alpha = 0.0;
[self.view addSubview:DialogView];
The UILabels all displaying as expected. As is the problem UIButton. I can see it I just can't interact with it!?!
DialogView's interface:
#class MyViewController;
#interface DialogView : UIView {
IBOutlet UILabel *nameLabel, *noteLabel, *amountLabel;
IBOutlet UIImageView *arrowView;
IBOutlet UIButton *okButton;
MyViewController *myVC;
}
#property (nonatomic, retain) UILabel *nameLabel, *noteLabel, *amountLabel;
#property (nonatomic, retain) UIImageView *arrowView;
#property (nonatomic, assign) MyViewController *myVC;
#property (nonatomic, retain) UIButton *okButton;
- (IBAction)okButtonPressed:(id)sender;
#end
And DialogView's implementation:
#import "DialogView.h"
#import "MyViewController.h"
#implementation DialogView
#synthesize nameLabel, noteLabel, amountLabel, arrowView, okButton;
#synthesize myVC;
- (void)dealloc {
[nameLabel release];
[noteLabel release];
[amountLabel release];
[arrowView release];
[okButton release];
[super dealloc];
}
- (id)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
// Initialization code
}
return self;
}
- (id)initWithCoder:(NSCoder *)decoder {
if (self = [super initWithCoder:decoder]) {
NSLog(#"DialogView initWithCoder called");
}
return self;
}
- (IBAction)okButtonPressed:(id)sender {
NSLog(#"pressed DialogView OK button");
[self.myVC.navigationController popViewControllerAnimated:YES];
}
- (void)drawRect:(CGRect)rect {
// Drawing code
}
#end
I thought that we should use -setTitle:forState: in order to set button's title ?
An other thought, did you check that the button's frame is not CGRectZero ? And by the way, all the frames for the view in the hierarchy ? And check that one superview in the hierarchy is not user interaction disabled ?
And, I think imageView does not respond to touches, do you have one in your code ?
I was just having more or less the same problem and I found that my containing view did not have "User Interaction Enabled".
Hope this helps.
Do you maybe have two buttons on top of one another? Change the IB project window to the detail view and see if your view has more buttons than you are expecting. Maybe you've wired up a button that's not actually getting the press you're expecting.