I have a segmented controller that I have made using the interface builder it looks like this
Sometimes I set it to be four using this
[segmentedControl insertSegmentWithTitle:#"Dinner" atIndex:2 animated:YES];
[segmentedControl insertSegmentWithTitle:#"Latenight" atIndex:3 animated:YES];
Which works and is fine, but here is where my problem comes up, sometimes I just want to have breakfast and dinner and late night but no lunch. However I still want dinner to be at index 2 and late night at index 3. So the code I have doesn't need to change multiple times depending on how many indexes there are. I am aware of [segmentedControl setEnabled:NO forSegmentAtIndex:0]; But it doesn't look good and is not what I am trying to do?
Basically is there a way I can hide the lunch index so that dinner is still at index 2, and/ or set the dinner to index 2 even though there is no lunch segment?
Thanks for the help in advance!!! :)
EDIT
-(IBAction)selectMeal:(id)sender{
switch (((UISegmentedControl *) sender) .selectedSegmentIndex) {
case 0:
if ([dayInfo isEqualToString:#"Monday"]) {
deliString = #"//day[#name='monday']/meal[#name='LUNCH']/counter[#name='Deli']/dish/name";
}
case 1:if ([dayInfo isEqualToString:#"Monday"]) {
deliString = #"//day[#name='monday']/meal[#name='Dinner']/counter[#name='Deli']/dish/name";
}
Tried this:
indexBreakfast = -1;
indexLunch = 0;
indexDinner = 1;
[segmentedControl removeSegmentAtIndex:indexBreakfast animated:YES];
[segmentedControl insertSegmentWithTitle:#"Dinner" atIndex:indexDinner animated:YES];
Ew please don't use that approach. I know you want to be able to know which type corresponds with which index without a lookup, but it's just lazy.
Here's another approach. When you determine which options you are going to display, store an array of the options (either wrapped enum values, the string titles, whatever). When your target action is fired, grab the type from the array at the index of the selected segment. Done.
In your class, make a property to store the order
#property (nonatomic, strong) NSArray *mealStrings;
Then when you have determined which meals you want and the order, make an array with the values
self.mealStrings = #[#"Breakfast", #"Lunch"];
... and initialize the UISegmentedControl ...
self.segmentedControl = [[UISegmentedControl alloc] initWithItems:self.mealStrings];
Then when you need to know which meal, you can access the type with
NSString *mealName = self.mealStrings[self.segmentedControl.selectedSegmentIndex];
There is no way to hide a segment. It must either be removed or disabled. And since you want to remove the segment, you need a good way to deal with segment indexes having different meaning depending on the visible segments.
One option would be to define an ivar for each possible segment and set it to the corresponding segment index as you build and adjust the segmented control.
Lets say you have four possible segments - breakfast, lunch, dinner, and late night. Add these four ivars:
NSInteger indexBreakfast, indexLunch, indexDinner, indexLateNight;
Now when you build the segmented control, set these four ivars to match the actual segment index of the corresponding segment. Assign -1 to the ivar if the segment isn't visible.
Now your segment handling code can be like:
-(IBAction)selectMeal:(UISegmentedControl *)control {
NSInteger index = control.selectedSegmentIndex;
if (index == indexBreakfast) {
// handle breakfast
} else if (index == indexLunch) {
// handle lunch
} else if (index == indexDinner) {
// handle dinner
} else if (index == indexLateNight) {
// handle late night
}
}
If you add, remove, or reorder segments as the app runs, simply update the four ivars and the rest of the code will do the right thing.
Related
This is my simple UITest (customizing order of tabs in tabbarcontroller):
func testIsOrderOfTabsSaved() {
let app = XCUIApplication()
let tabBarsQuery = app.tabBars
tabBarsQuery.buttons["More"].tap()
app.navigationBars["More"].buttons["Edit"].tap()
tabBarsQuery.buttons["Takeaway"].swipeLeft()
tabBarsQuery.buttons["In Restaurant"].swipeLeft()
//here, how to get position of moved button with text "In Restaurant"?
NOTE:
It is possible to get XCUIElement from XCUIElementQuery by index. Can I do this fro the other way?
It seems that the queries automatically return in order based on position on screen.
for i in 0...tabsQuery.buttons.count {
let ele = tabsQuery.buttons.elementBoundByIndex(i)
}
Where the index i represents the position of the button in the tab bar, 0 being the leftmost tab, i == tabsQuery.buttons.count being the rightmost.
You have various ways to create a position test. The simplest way is to get buttons at indices 0 and 1, then get two buttons by name and compare the arrays are equal: (written without testing)
let buttonOrder = [tabBarsQuery.buttons.elementAtIndex(0), tabBarsQuery.buttons.elementAtIndex(1)]
let takeawayButton = buttons["Takeaway"];
let restaurantButton = buttons["In Restaurant"];
XCTAssert(buttonOrder == [takeawayButton, restaurantButton])
Another option is to directly get the frame of each button and assert that one X coordinate is lower than the other.
To answer your specific question about getting the index of an XCUIElement in a XCUIElementQuery, that's absolutely possible. Just go through all the elements in the query and return the index of the first one equal to the element.
An XCUIElement alone isn't able to tell you its position in within the XCUIElementQuery. You can search the XCUIElementQuery to discover its offset if you know something about the XCUIElement. In the below let's imagine that "More" is the identifier (change 'identifier' to 'label' if that is what you're working with).
If you want to find the offset of the "More" button (as posted in the original question) then:
var offsetWithinQuery : Int? = nil // optional since it's possible the button isn't found.
for i in 0...tapBarsQuery.buttons.count{
if tapBarsQuery.elementAtIndex(i).indentifier == "More" {
offSetWithinQuery = i
}
After the above loop exits, you'll either have the offset or it'll be nil if "More" isn't found.
I know this is a startlingly stupid question, but I can't figure it out. Every answer involves a UISearchBar, which is not what I've got.
I'm trying to display 2 sets of results on one TableViewController.
Results to display
1) everything in my managedObjectContext which is set up in my viewDidLoad
2) a filtered set of results if a predicate is selected.
On MyTableViewController, I have a popover which instantiates when I click a UIBarButtonItem on MyTableViewController. On the popover, I set a predicate on MyTableViewController.
Basically, I'd like to toggle what's displayed and that display toggle is driven by whether my variable is nil (everything displays) or filtered (variable sets a predicate).
Have two NSArray properties allValues and filteredValues. Set up all your delegate/dataSource properties using your filteredValues array.
Next, do something like this when you first get all your data:
self.allValues = [someController fetchAllValues];
self.filteredValues = self.allValues;
[self.myView.tableView reloadData];
Last, alter your filteredValues array whether or not a predicate is selected:
if (self.selectedPredicate) {
self.filteredValues = [self.allValues filteredArrayUsingPredicate:self.selectedPredicate];
} else {
self.filteredValues = self.allValues;
}
[self.myView.tableView reloadData];
In the settings section of my app the user has the option to change the language of the app. So when the user chooses spanish as his primary language the app show the content in spanish after he did an app restart but I want to change the language on the fly. This works for the main content like a TableView because I simply can reload the data but the language in my TabBarController does not change because I don't know how.
So I want to update (or better call it a reset) the TabBarController. After the reset it should display all navigation points in the new language.
My idea was to remove the current TabBarController and initialize a new one. Is this possible? Or is there a better way?
I am not an native english speaker so if my explanations aren't clear enough, just tell me and I'll try to rephrase them.
It might look scary and complicated because of my long post, But it really isn't, it is just long because I thought it would be better to also explain how to do it, instead of just giving a few lines of code.
You can achieve what you want using UITabBarController properties.
UITabBarController have a property called tabBar, which is the actual UITabBar.
One might think that in order to achieve what you want, you should edit this property,
HOWEVER, editing this property would cause an exception.
From apple's UITabBarController documentations, regarding the tabBar property:
You should never attempt to manipulate the UITabBar object itself stored in
this property. If you attempt to do so, the tab bar view throws an exception.
So you should never attempt to edit this property at runtime.
After that word of warning, here is what you should do-
UITabBarController also have a property called viewControllers, which is an NSArray who holds reference to the view controllers that being displayed by the tab bar.
This property CAN be modified at runtime, and changes applied to it are updated instantly in the tab bar.
However, for your case, you don't need to modify this property,
But I thought you should know that so if in some situation you will need to add or remove some items from your tab bar, you'll know that can do it.
What you do want to do, is iterate through the objects of that array to access the view controllers themselves.
UIViewController have a property called tabBarItem which represents the UITabBarItem of the view controller.
So what we are basically doing, is getting the tab bar item of the view controller, but instead of getting it from the UITabBarController itself, we are getting it directly from each view controller.
Each UITabBarItem has a title property, and this is what you want to change.
So now, after that long introduction, let's get to the actual code.
I think a pretty easy way to achieve what you want is to iterate thru the viewControllers array, and have some switch statement in there that would change the title.
As in any programming situations, this can be done in countless other ways, so you might have a better way to implement it than my example below, but this should do the trick.
Each view controller that being displayed in a tab bar controller, have a reference to that tab bar using the property tabBarController
So you can run this code in any of the view controllers that being displayed in the tab bar, and simply use self.reference to get a reference to it.
Add this somewhere after the language have changed-
for (int i = 0; i < [self.tabBarController.viewControllers count]; i++) {
if([self.tabBarController.viewControllers[i] isKindOfClass: [UIViewController class]]) {
UIViewController *vc = self.tabBarController.viewControllers[i];
switch(i) {
case 0:
vc.tabBarItem.title = #"primero";
break;
case 1:
vc.tabBarItem.title = #"secondo";
break;
}
}
}
What we are basically doing, is running a for loop that iterating thru all of the items in the array,
The items in the array are in the same order that they appear on the tab bar,
then we use a switch statement to change the title for the view controller in the corresponding position,
Since array have index 0, the first view controller is at position i=0 and the last one is at one less than the count of items in the array.
Some might argue that my if is unnecessary,
Since we already know that this array holds only view controllers, there is no need to check if the item at that position is of UIViewController class, or a subclass of it.
They might be right, but I always say it's better to be safe than sorry.
Of Curse I would also include in your code something to actually check to what language the user have chosen.
The example above changes the titles to spanish, regardless of the user's choice.
Hope it helps mate,
Good luck
#AMI289 gave a good idea.
Make an extension for UITabBarController and do a loop there. Can call anywhere from the tabBarControllers stack.
In my case after the tabBarController goes navigationController.
// MARK: - UITabBarController
extension UITabBarController {
func changeTitleLocale() {
guard let viewContollers = self.viewControllers else { return }
for (index, navVC) in viewContollers.enumerated() {
if let view = navVC as? UINavigationController {
if let topView = view.topViewController {
if topView.isKind(of: ProfileVC.self) {
self.tabBar.items?[index].title = "tab_profile"
} else if topView.isKind(of: ChatVC.self) {
self.tabBar.items?[index].title = "tab_chat"
} else if topView.isKind(of: PicturesVC.self) {
self.tabBar.items?[index].title = "tab_pictures"
} else if topView.isKind(of: VideosVC.self) {
self.tabBar.items?[index].title = "tab_videos"
}
}
}
}
}
}
Then, when we change a language just run it:
self.tabBarController?.changeTitleLocale()
I'm new to Objective-C and Xcode, and I have one problem, I tried looking in the Internet, but didn't find anything.
I have "game" and there I have a screen with two text fields, button and text view.User inputs integer values and taps the button. After tapping the button some functions(or, methods) are called. Method that is called after typing the button:
- (IBAction)okButtonTapped:(id)sender {
int save1=100;
int save2=100;
int save13=1;
int save22=1;
int save12=1;
int save23=1;
while(save13 !=0 && save23 !=0){
[self yourturn:&save1 heap2:&save2];
save12= save1;
save22=save2;
[self compturn:&save12 heap2:&save22];
save13=save12;
save23=save22;
save1=save13;
save2=save23;
}
}
Here some methods are called. And in this methods I use this code to save values from textfields that user inputs:
_heapNumberInt=[self.heapNumberTextField.text intValue];
_thingsNumberInt=[self.thingsNumberTextField.text intValue];
And the question is how to make users input new values in the textfield every time when there is new iteration in while loop?
Sorry for my English(it's not my native language) and for my long question.
All project you can download here
P.S. "game" is very simple: there are 2 heaps with 100 things each, user chooses his turn and then he inputs values: heap number(1 or 2 heap) and number of things he wants to take from the heap. Then there is computer's turn. And looser is someone who can't take things from any heap. It is real game called NIM.(but here I made only 2 heaps(not 3)).
Probably you need to read Event Handling Guide
https://developer.apple.com/library/ios/documentation/EventHandling/Conceptual/EventHandlingiPhoneOS/Introduction/Introduction.html#//apple_ref/doc/uid/TP40009541
About the question, for setting focus to the input you should use
[self.heapNumberTextField becomeFirstResponder];
UPDATE:
As I understand you need to:
_heapNumberInt = [self.heapNumberTextField.text intValue]; // get value
[self.heapNumberTextField setEditable:NO]; // disable editing to calculate
[self calculate];
self.heapNumberTextField.text = #""; // clean UITextField
[self.heapNumberTextField setEditable:YES]; // allow editing
[self.heapNumberTextField becomeFirstResponder]; // set focus to the textfield
I seem to be missing something very simple here.
I have a UIViewController which contains a UISegmentControl with two segments ("shown" & "not shown").
The user selects one in this view controller and fills in some information into text fields which all gets saved to a table view controller.
When I click on a cell to edit the information, I can't get the selected segment to show, so if I select "Not shown" in this cell when saving, I want it to show "Not Shown" selected when I edit the cell.
I then of course want to provide the user the ability to change from "Not Shown" to "Shown" with the UISegmentControl.
My code for saving the UISegment Control in the save method of the creating View Controller is:
contract.wasShown = #(self.isShownSegment.selectedSegmentIndex == 0);
I'm using Core Data here.
So in the detailViewController, I have tried a few things but with no luck (it's always showing the first segment).
if ([contract.wasShown boolValue]) {
contract.wasShown = #(self.isShownSegment.selectedSegmentIndex == 0);
}
else {
contract.wasShown = #(self.isShownSegment.selectedSegmentIndex == 1);
}
What do I need to do to get the selected segment shown and then what should I put in the save method of the Detail View to change that selection if possible?
Thanks!
Sorry all - this was just me being stupid.
Implemented with the following code in viewDidLoad:
if ([contract.wasShown boolValue])
{
self.isShownSegment.selectedSegmentIndex = 0;
}
else
{
self.isShownSegment.selectedSegmentIndex = 1;
}