I do not want the user to be able to select the first few characters of my UITextView. I have tried subclassing it and noticed methods such as -setSelectedRange: and -setSelectedTextRange:. Both are called at different times but it seems like it's the latter that I need.
The -setSelectedTextRange: method takes a UITextRange object, which has a UITextPosition property called "start". This sounds like what I want but I cannot write to it, and there are no classes for this object.
Does anyone have any ideas on how I can do this? FWIW, I'm trying to replicate what Facebook have on their "Check-In" view on their iPhone app.
Thanks in advance!
I'm not personally familiar with the functionality of the Facebook app Check-In view, but based on your description, it sounds like you need something like this in your subclass:
- (BOOL)becomeFirstResponder
{
if ([super becomeFirstResponder]) {
// Select text in field.
[self setSelectedTextRange:[self textRangeFromPosition:[self positionFromPosition:self.beginningOfDocument offset:1] toPosition:self.endOfDocument]];
return YES;
}
return NO;
}
In particular, note the "offset:1" argument. You should be able to use this to set the start of your selected text range. Also, you'll want to make sure that the new text range you specify is valid for the number of characters that are in the text field.
Related
I have UITextField that I have formatting code attached on textFieldDidEndEditing:. This works fine, but when I first load the text field with a text value (someTextField.text = #"...") the formatting doesn't happen. Of course, I can add another formatter there, but it seems kind of repetitive.
Is there a way to make all changes to a UITextField, programmatic or user originated, have formatting applied automatically?
Just run the same method from both places...
- (void)setTextFieldWithText:(NSString *)text {
//do formatting here...
self.textField.text = formattedText;
}
You can either add UITextFieldDidChangeNotification or just add a observer(using the addObserver method) to observe changes to the textfield. Choose which suits your approach. Both of them does cut the repetitive code. KVO - concept related to your question.
you might get some idea if you take a look at the following links
UITextFieldDidChangeNotification - How do i notify changes in UITextField?
addObserver method - detecting the change of content of UITextField when the change is not made by the keyboard
Note: Although the classes of the UIKit framework generally do not support KVO, you can still implement it in the custom objects of your application, including custom views.
When a user taps on a UISegmentedControl and changes which segment is selected, I want to perform some validation. If the validation fails, I want to 'undo' their selection, and re-select the item that they previously had selected.
What's the easiest way to do this? I think I need something like
- (BOOL) segment:(UISegmentedControl *)seg shouldSelectSegmentAtIndex:(NSInteger)newIndex`
but I was looking at the Apple Docs, but I didn't see anything like that - really I didn't see anything with will in it at all. Will I have to create a category or subclass to do this, or am I just missing it?
I suppose I could add an ivar that holds the selected segment index after it has been validated, and then call [mySegmentedControl setSelectedSegmentIndex:myIvar]; if validation fails, or myIvar = [mySegmentedControl selectedSegmentIndex]; when it passes, but that feels a little messier. It's also a bit of a pain if I have a lot of segmented controls on the same screen. I believe if I do create my own subclass, I'll have to do something like this though.
EDIT:
Other programming languages I've used have natively supported an 'undo' feature, without the programmer having to implement the undo on his own. I'm looking to see if anyone is aware of something like that for Objective-C. If it does not exist, does anyone know of a better way to implement it other than the ivar method I described above?
I don't believe there really is an elegant way to do that without subclassing. But since there are no subclassing notes on UISegmentedControl, that could be an option. Override setSelectedSegmentIndex, where you check through delegation whether that index should be selected. If it should, call super's implementation. If not, just do nothing.
This does assume that there are no internal methods that mess things up (and which you can't override).
Im not exactly sure what you are asking, but if I understand correctly I do believe this would do the trick:
[mySegmentedControl addTarget:self action:#selector(segmentChanged:) forControlEvents:UIControlEventChanged];
- (void)segmentChanged:(id)sender
{
if (myIvar != validated){
[mySegmentedControl setSelectedSegmentIndex:defaultSegment];
}
}
What's the difference between declaring a UIButton in Xcode like this:
- (IBAction)testButton;
and declaring a button like this:
- (IBAction)testButton:(id)sender;
I understand that in the .m file you would then implement the buttons accordingly, as shown below:
- (IBAction)testButton
{
// insert code here..
}
and setting it up like this:
- (IBAction)testButton:(id)sender
{
// insert code here..
}
Is there any additional things you can do by declaring the button with :(id)sender, is there some additional stability, or is there no difference?
With :(id)sender you are able to access the button itself through the sender variable. This is handy in many situations. For example, you can have many buttons and give each a tag. Then use the [sender tag] method to find which button was tapped if many buttons are using this IBAction.
- (IBAction)someMethod:(id)sender {
// do stuff
}
Using (id)sender, you have a reference to who sent the method call. Please note, this doesn't have to be limited to a UIButton.
If you're created this method via control-dragging from the storyboard an only hooking up a single button, then sender is basically useless (it will always be the same), and should probably be marked as unused:
#pragma unused (sender)
(The compiler can better optimize your code if you do this.)
However, there's nothing wrong with hooking up several UI elements to the same IBAction method. You can then distinguish the sender via:
[sender tag]
...which returns an int that was either set via the storyboard or programmatically.
Moreover, you can call this method elsewhere in your class. You can either pass nil as the sender, or you can pass it a particular UI element in order to force it into the results you've coded for objects of that tag.
Nonetheless, if you plan to call the method with a nil argument, you can always throw:
if(!sender)
... into the method in order to handle special logic for when the method has been invoked programmatically as opposed to via user interaction.
It allows you to know which button you are working with. I have posted a simple example for a card game below
- (IBAction)flipCard:(id)sender {
[self.game flipCardAtIndex:[self.cardButtons indexOfObject:sender]];
self.flipCount++;
[self updateUI];
}
This method is used for a card flipping game. There are multiple buttons on the screen representing different cards. When you hit the button, a card in the model must be flipped. We know which one by finding the index of the variable sender
I can use
-(BOOL)textViewShouldBeginEditing:(UITextView *)firstTextView {
return NO;
}
to stop a textView from being edited via the keyboard.
However if I try to use another
-(BOOL)textViewShouldBeginEditing:(UITextView *)secondTextView {
return NO;
}
I get an error for the redefinition of the textViewShouldBeginEditing.
I am sure it is something silly I am doing with the delegate method.
The error is telling you precisely what's wrong. You're redefining the method.
The method takes a UITextView* as an argument precisely so you can tell which text view is asking the question, so you can tailor your response. Of course if you want to always say NO to all text views then you can ignore the parameter. In any case, just delete your duplicate definition and you'll be fine.
note: This is an expansion (and clarification) of a question I asked yesterday.
I am conducting a research project where I want to record all of the user's touches in the iPhone app. After the experiment, I will be able to download the data and process it in either Excel or (more likely) Matlab and determine how many times they clicked on certain buttons, when they clicked certain buttons, etc. To do this, I would need to know:
a) When they touched
b) Where they touched
c) Which view they touched
The first two are easy, but the third I am having trouble with. I know I can do this to get the reference to the UIView that was touched:
CGPoint locationPoint = [[touches anyObject] locationInView:self];
UIView* viewYouWishToObtain = [self hitTest:locationPoint withEvent:event];
However, that will just give me a pointer to the view, not the name of the view that was touched. I could assign each view a tag, but then every time I create a new view I would need to remember to tag it (or, alternatively, log the address of each view when initialized and log it when the view is touched). Subclassing UIView and adding an automatic tag isn't really an option since I'm creating other UIButtons and UISliders and would need to subclass those also, which doesn't seem like a very good solution.
Does anyone know of a clean, easy way to do this?
For "Which view they touched", what information do you need?
Perhaps you could use a category to add a method to UIView. This method would generate a string containing information about the view. Such as:
its type e.g. UIButton etc.
its size and position
the title of the view, if it has one (e.g. the button title)
the parent view type and title
other stuff e.g. is the view enabled, what state it is in. anything you like.
For example: "Type:UIButton Title:"Back" Rect:{3,5,40,25}" or some such string.
This is very clean and gives you quite a lot of information to be going with.
You could add a category to UIView which would then be inherited by all UIView descended objects, although I'm not sure its any more efficient than tagging. Since a category can override methods then you could override init methods for automatic tagging I suppose.
http://macdevelopertips.com/objective-c/objective-c-categories.html
I'm not sure what you mean by the "name" of the view. If you mean the view name in Interface Builder, I don't believe it includes that in the instantiated objects. You could use the Tag attribute which is included, but that's just a number and not a name.