I have an tabBarController app with 2 tabBarItems.
each viewControllers contains tableView.
On didSelectRowAtIndexPath i am loading the detailview with this lines of code:
detailViewController = [[DetailViewController alloc] initWithNibName:#"DetailViewController_iPad" bundle:[NSBundle mainBundle]];
detailViewController.selectedDetail = [selectedDetail valueForKey:#"cardText"];
detailViewController.selectedCardTitle2 = [selectedCardTitle valueForKey:#"cardTitle"];
detailViewController.selectedRow2 = [self.tableViewInbox indexPathForSelectedRow];
detailViewController.detailCardsArray = allCards;
detailViewController.detailAllFetchedCards = allFetchedCards;
detailViewController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[inboxViewController presentModalViewController:detailViewController animated:YES];
Problem is, when detailView is loaded(is the actual shown viewController) and i change to the other tabBarItem, the detailView DOES NOT DISMISS. That means, that i cant load the detailView again, if didSelectRowAtIndexPath is called.
In my AppDelegate i have the method
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController {
In this method i will check up, if the detailView is the actual shown viewController.
And if it is, and the tabBarItem changes, THEN dismiss the DetailView.
Now my question is: How can I CHECK, if the detailView is loaded (current shown view) or not?
The documentation tells us that the detailView becomes a child of the presenting view. The presenting view controller will have it's modalViewController property updated to point to the presented view. Also, the modal view's parentViewController will be updated to point to the presenting view.
So, you could check these properties to see whether or not the modal view is displayed or not.
Related
I am trying to load multiple models(aggregation) on to the forge viewer(v.6.x) initially while loading, but I want to show only one model and other models as hidden by default(can be with ghost view). Later when user clicks on eye icon from model browser, then that model should be visible/hidden.
I tried calling viewer.hideModel(modelId) after loading the model. But even though the model is showing in model browser, when I click on it, it says error model is not loaded.
var showModel = false;
this.viewer.loadModel(url, {globalOffset: { x:0, y:0, z:0 }, modelNameOverride: modelName}, () =>
{
this.isModelLoaded = true;
this.viewer.caller = this;
this.addEventListenersToViewer();
if(!showModel){
this.viewer.hideModel(modelId); // This is to hide the model by default after loading.
}
},
errorMsg => {
this.isModelLoaded = false;
this.viewer.container.style.opacity = 0;
this.modelLoadError(this.fetchTranslationByKey('getModelError'));
}
);
Expected behavior is to allow user to select from model browser, which models to show/hide on the viewer among all the models loaded initially(linked models should be hidden by default).
Current result I am getting is the linked models are showing in the model browser but when I click on that it says - Error Model is not loaded
A few issues here:
When using arrow function the context that this points to is different so be careful with that
how did you obtain the modelId? Instead of using arbitrary counter better to iterate the model array via Viewer.impl.modelQueue()
I am unable to replicate the model not loaded error with model browser. Can you provide more details or a live sample (jsfiddle/jsbin)?
I am new to swift i am using storyboard and have used navigationcontrollers to connect from one viewcontroller to another. I want to send the name of the image clicked to the next viewcontroller which is connected modally in storyboard from the imageView. I searched lot about transferring data from oneviewcontroller to another viewcontroller connected with navigationcontroller modally but no solution was available. Please let me know if any of the code is required as i dont know how to go ahead with it. I know this might be silliest question but posting this after searching a lot on net.
EDIT according to #uraimo reply.
Do i need to provide name to every segue i created on storyboard?.
I have 2 fixed images on viewcontrollerA and i have placed a uibutton with transparent background and no text on each of them and then ctrl drag to navigation controller of viewcontrollerB for presenting modally and unwinding the backbutton i.e. UIBarButtonItem to viewcontrollerA by ctrl drag the back button of viewcontrollerB to exit of the viewcontrollerB and unwinding it.
This is how i have created navigation from any of the image click out of 3 images of viewcontrollerA to viewcontrollerB and back to viewcontrollerA on back button click of viewcontrollerB.
Please let me know if i am doing anything wrong and will your prepareForSegue code be useful in accomplishing my task.
Basically, both using IB or when you do it programmatically, you have to configure your new viewcontroller with all the data it needs before the segue is performed (or the controller is presented via code).
In your case, just set the image name (your custom view controller class YourViewController should have a specific String property to hold this value) overriding prepareForSegue in the current view controller class:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "yourModalSegueIdentifier" {
let imgName= (sender as! UIImageView)
let destination = segue.destinationViewController as UINavigationController
let yourController = destination.topViewController as YourViewController
yourController.imageName= <name here>
}
}
This solves the passing data question.
But in your case, you need the name of the clicked image, and that can be only obtained adding a click event through a UIGestureRecognizer to the UIImageView.
So, you'll need a uigesturerecognized that on click will perform the segue you've created. And also, you will not be able to get the name of the image asset (the one you use the creating an UIImage using imageNamed:) because it's not available anymore, and yo'll have to use the accessibilityIdentifier.
This makes everything way more complicated, it seems it could be done for the most part graphically here and here(but it's not really clear how to do it), but it's usually done via code.
Simplifying it a bit using a global variable:
var currentImage = ""
func viewDidLoad(){
...
...
let aTap = UITapGestureRecognizer(target: self, action: Selector("imageTapped:"))
aTap.numberOfTapsRequired = 1
//For every image, configure it with recognizer and accessibilityId:
firstImage.userInteractionEnabled = true
firstImage.addGestureRecognizer(aTap)
firstImage.accessibilityIdentifier = "firsImage"
...
}
func imageTapped(recognizer:UITapGestureRecognizer) {
let imageView = recognizer.view as! UIImageView
currentImage = imageView.accessibilityIdentifier
self.performSegueWithIdentifier("yourModalSegueIdentifier", sender: self)
}
And change this:
yourController.imageName= <name here>
to this:
yourController.imageName= currentImage
Update:
Do i need to provide name to every segue i created on storyboard?
Yes, it's the only way to identify them, every UIStoryboardSegue has an identifier. But remember, segues are not the only way to go from a controller to another, if you do it completely programmatically (no segues) you usually call "presentViewController". Segues are a storyboard concept.
Again, regarding the segue name/identifier, you didn't need it until now because you never referenced that segue from your code, you need it for both prepareForSegue and performSegueWithIdentifier. Just select the segue and give it a name on the right inspector pane.
The structure you describe seems ok, the only thing it's that i'm not so sure that the UIButtons are really needed, try with a modal segue from the imageview or directly from the viewcontroller to the destination view controller.
Update 2:
If you are starting and need a free course that will teach you the basics and also make you build a few interesting ios apps i recommend hackingwithswift.
check out how I did this
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
super.prepare(for: segue, sender: sender)
switch(segue.identifier ?? "") {
case "AddItem":
let destination = segue.destination as? UINavigationController
guard let itemViewController = destination?.topViewController as? ItemViewController else {
fatalError("Unexpected destination: \(segue.destination)")
}
itemViewController.collection = collection
case "EditCollection":
guard let collectionViewController = segue.destination as? EditCollectionViewController else {
fatalError("Unexpected destination: \(segue.destination)")
}
collectionViewController.collection = collection
default:
fatalError("Unexpected Segue Identifier; \(segue.identifier)")
}
}
I have a UISplitViewController which presents a UIViewController with the following code:
self.splitViewController.preferredDisplayMode = UISplitViewControllerDisplayModePrimaryHidden;
UIViewController *quiz = [[UIViewController alloc] initWithNibName:nil bundle:nil];
[self showDetailViewController:quiz sender:self];
I want to be able to present more view controllers from the already presented detail view controller that has been presented with -showDetailViewController. Do I simply call -presentViewController:animated:completion: or am I able to replace the current detail view controller with the view controller I would like to present?
The problem that I am have is that my quiz vc has a button with the following code that brings the user back to the UISplitViewController. When I use this code from the vc that the quiz vc presented with -presentViewController:animated:completion: nothing happens, but if this code is executed directly from the quiz vc it takes the user back to the main split view controller.
self.splitViewController.preferredDisplayMode = UISplitViewControllerDisplayModeAllVisible;
UIViewController *mainDetailVC = [[UIStoryboard storyboardWithName:#"Main" bundle:[NSBundle mainBundle]]
instantiateViewControllerWithIdentifier:#"mainDetailVC"];
[self.splitViewController showDetailViewController:mainDetailVC sender:self];
I have a UIWebview contains a html "select" tag, which is shown as a on the screen.
When I click the dropdown, the UIWebview brings up a UIWebSelectSinglePicker View automatically, which is shown as .
I want to change the picker view background color and text color. How can I achieve this goal?
I tried to listen on UIKeyboardWillShowNotification event, but at that moment, this view has not been created.
Thanks in advance for any helps.
I managed to resolve the issue myself.
If someone also want to change the UIPickView on the fly, please take a look:
First, add a listener on UIKeyboardWillShowNotification event.
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(_pickerViewWillBeShown:) name:UIKeyboardWillShowNotification object:nil];
Second, when notification fired, call change background color method after delay. <-- This is very important, if call method without delay, the pickview does not exist at that moment.
- (void)_pickerViewWillBeShown:(NSNotification*)aNotification {
[self performSelector:#selector(_resetPickerViewBackgroundAfterDelay) withObject:nil afterDelay:0];
}
Third, go through the UIApplication windows and find out pickerView. And you can change what ever you want for pickerView.
-(void)_resetPickerViewBackgroundAfterDelay
{
UIPickerView *pickerView = nil;
for (UIWindow *uiWindow in [[UIApplication sharedApplication] windows]) {
for (UIView *uiView in [uiWindow subviews]) {
pickerView = [self _findPickerView:uiView];
}
}
if (pickerView){
[pickerView setBackgroundColor:UIColorFromRGB(0x00FF00)];
}
}
(UIPickerView *) _findPickerView:(UIView *)uiView {
if ([uiView isKindOfClass:[UIPickerView class]] ){
return (UIPickerView*) uiView;
}
if ([uiView subviews].count > 0) {
for (UIView *subview in [uiView subviews]){
UIPickerView* view = [self _findPickerView:subview];
if (view)
return view;
}
}
return nil;
}
Hope it will help.
I believe I've come up with an alternate solution to this problem. There are certain circumstances with the other solution proposed where the label colours appear incorrect (using the system default instead of the overridden colour). This happens while scrolling the list of items.
In order to prevent this from happening, we can make use of method swizzling to fix the label colours at their source (rather than patching them after they're already created).
The UIWebSelectSinglePicker is shown (as you've stated) which implements the UIPickerViewDelegate protocol. This protocol takes care of providing the NSAttributedString instances which are shown in the picker view via the - (NSAttributedString *)pickerView:(UIPickerView *)pickerView attributedTitleForRow:(NSInteger)row forComponent:(NSInteger)component method. By swizzling the implementation with our own, we can override what the labels look like.
To do this, I defined a category on UIPickerView:
#implementation UIPickerView (LabelColourOverride)
- (NSAttributedString *)overridePickerView:(UIPickerView *)pickerView
attributedTitleForRow:(NSInteger)row
forComponent:(NSInteger)component
{
// Get the original title
NSMutableAttributedString* title =
(NSMutableAttributedString*)[self overridePickerView:pickerView
attributedTitleForRow:row
forComponent:component];
// Modify any attributes you like. The following changes the text colour.
[title setAttributes:#{NSForegroundColorAttributeName : [UIColor redColor]}
range:NSMakeRange(0, title.length)];
// You can also conveniently change the background of the picker as well.
// Multiple calls to set backgroundColor doesn't seem to slow the use of
// the picker, but you could just as easily do a check before setting the
// colour to see if it's needed.
pickerView.backgroundColor = [UIColor yellowColor];
return title;
}
#end
Then using method swizzling (see this answer for reference) we swap the implementations:
[Swizzle swizzleClass:NSClassFromString(#"UIWebSelectSinglePicker")
method:#selector(pickerView:attributedTitleForRow:forComponent:)
forClass:[UIPickerView class]
method:#selector(overridePickerView:attributedTitleForRow:forComponent:)];
This is the Swizzle implementation I developed based off the link above.
#implementation Swizzle
+ (void)swizzleClass:(Class)originalClass
method:(SEL)originalSelector
forClass:(Class)overrideClass
method:(SEL)overrideSelector
{
Method originalMethod = class_getInstanceMethod(originalClass, originalSelector);
Method overrideMethod = class_getInstanceMethod(overrideClass, overrideSelector);
if (class_addMethod(originalClass,
originalSelector,
method_getImplementation(overrideMethod),
method_getTypeEncoding(overrideMethod))) {
class_replaceMethod(originalClass,
overrideSelector,
method_getImplementation(originalMethod),
method_getTypeEncoding(originalMethod));
}
else {
method_exchangeImplementations(originalMethod, overrideMethod);
}
}
#end
The result of this is that when a label is requested, our override function is called, which calls the original function, which conveniently happens to return us a mutable NSAttributedString that we can modify in anyway we want. We could completely replace the return value if we wanted to and just keep the text. Find the list of attributes you can change here.
This solution allows you to globally change all the Picker views in the app with a single call removing the need to register notifications for every view controller where this code is needed (or defining a base class to do the same).
I have a slide view controller setup.
When viewing the app in IOS7 the status bar is shown and translucent so it is shown with the content.
Is there something I should be doing to offset the content below the status bar for this specific View Controller in my storyboard?
Awarded answer to #Idan for the suggestion but as this is a table view controller had to accomplish differently:
-(void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:YES];
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"7")) {
self.tableView.frame = CGRectMake(0, 20, self.tableView.frame.size.width, self.tableView.frame.size.height-20);
}
}
I've solved it by introducing setting the table header view as a 20 point height view.
This code in viewDidLoad
UIView *headerView = [[UIView alloc] initWithFrame:CGRectMake(0.f, 0.f, self.tableView.frame.size.width, 20.f)];
headerView.backgroundColor = [UIColor whiteColor];
self.tableView.tableHeaderView = headerView;
Two different methods (depands on what you are trying to do):
Add this value to plist: "View controller-based status bar appearance" and set it to "NO". then you can code whatever you want (setStatusBarHidden etc.)
If you just want to move the view when it's iOS7 (status bar is above), in interface builder -> attribute inspector -> set delta y to -20 (so it would be below status bar).