Simple question though, but what is the correct way to get the text off my UITableViewCell?
With cell a UITableViewCell:
I know off cell.text, which gives exactly what I want, but is deprecated in iOS 3.0.
The only alternative I could find was cell.textLabel but this gives me the same (or almost?) as if I only used cell. Which is obviously not what I want.
So how can I get the text on my cell (what the user reads)? Or is it okay if I leave it as cell.text / will Apple accept it?
Simply use cell.textLabel.text = #"My Text"; and NSString *mytext = cell.textLabel.text as long as you are targeting 3.0 or above.
Related
I have a UITableView that is broken up into a user defined number of sections. Within each of these sections there are always 2 rows. Each of these two rows contains a UITextField which the user is able to edit.
What I need is a way of being able to access the data in these UITextFields at a later point. I was hoping it would be a simple problem however it's causing me a great deal of grief.
So far I have tried two approaches:
Attempt 1
I created two NSMutableArrays in which I added the UITextField objects to at index i (corresponding to the section it came from). I then tried to access the values by iterating through the array. This didn't work since the UITextFields kept getting wiped clean. Every-time I scroll down the table and the UITextField is out of view, when I go back it's contents have been wiped clean.
Attempt 2
I tried to get hold of the number of sections in the UITableView (this was fine). I then wanted to iterate through each section of the UITableView, recording the values in the rows of each. This is where I became unstuck since I'm not sure how to do this or if it's even possible.
I apologise if this is a naive question to ask, however I'm really struggling and would appreciate any advice.
Keep in mind that the text fields get reused as you scroll, so you don't really want to store references to them.
What you do instead, is to capture the information as it is entered. The easiest way to do this is to implement the textFieldDidEndEditing protocol method in the delegate.
The tricky part is figuring out which row the text field is in. The best way is to create a UITableViewCell subclass which has a NSIndexPath property. You can then set that when you configure the cell with tableview:willDisplayCell:forRowAtIndexPath:.
Then, in textFieldDidEndEditing, access the tableViewCell indexPath property through its superview. i.e.:
NSIndexPath indexPathOfParentCell = [(MyUITableViewCellSubclass *)self.superview indexPath];
Doing it this way allows you to know both the section and row of the cell.
Create your TextField in the cellForRow of the Table like so and give it a tag
UITextField * userField = [[[UITextField alloc] initWithFrame:CGRectMake(0, 12, self.view.frame.size.width -20, 20)] autorelease];
userField.tag = 1001;
userField.font = [UIFont fontWithName:#"HelveticaNeue-Bold" size:14];
userField.textAlignment = UITextAlignmentCenter;
userField.delegate = self;
userField.autocorrectionType = UITextAutocorrectionTypeNo;
userField.autocapitalizationType = UITextAutocapitalizationTypeNone;
userField.clearButtonMode = UITextFieldViewModeWhileEditing;
if (indexPath.row == 0)
[cell.contentView addSubview:userField];
then access the TextField like so:
UITextField *userField = (UITextField *)[[(UITableViewCell *)[(UITableView *)tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]] contentView] viewWithTag:1001];
Your "Attempt 1" should work OK if you keep the text field's text in your arrays rather than the text field itself. (Anything that tries to make a view or control into a data object has a good chance of going wrong.)
Whatever acts as a data source for your table view should be able to re-populate the scrolled cells according to section and row if the content is stored separately.
How would I go about adding text to a UITextView without replacing the previous text?
So far I have a UITextView and a UIButton that adds the text to the UITextView, but I would like the text field to append more text every time you hit the button instead of completely deleting the text and replacing it.
Here are some ways to overcome obstacles in iOS development:
Look at the documentation for the particular class you're trying to manipulate. In this case, UITextView documentation can be found within Xcode or online.
Command-Click on UITextView or any other object anywhere in your code, and it will bring you to the header file for that class. The header file will list every public method and property.
Look at your existing code. I'm assuming that since you have a button that adds text to a UITextView, you understand how to set its text. 99% of the time you'll find that any setter (mutator) methods will have a corresponding getter (accessor) method. In this case, UITextView has a method called setText: and a matching method just called text.
Finally, NSString has a convenience method called stringWithFormat: that you can use to concatenate (join) two strings, among other very useful things. %# is the format specifier for a string. For example, to combine two strings, stringOne and stringTwo, you could do the following:
NSString *string = [NSString stringWithFormat:#"%# %#", stringOne, stringTwo];
I will leave you to come up with the answer as to how to combine NSString stringWithFormat: and UITextField text and setText: to achieve what you'd like to accomplish.
Edit:
The OP was unable to figure out how to utilize the information above so a complete code sample has been provided below.
Assume you have synthesized property (possibly an IBOutlet) UITextView that you have initialized called myTextView. Assume also that we are currently in the method scope of the method that gets called (your IBAction, if you're using IB) when you tap your UIButton.
[myTextView setText:[NSString stringWithFormat:#"%# %#", myTextView.text, #"this is some new text"]];
Explanation: myTextView.text grabs the existing text inside of the UITextView and then you simply append whatever string you want to it. So if the text view is originally populated with the text "Hello world" and you clicked the button three times, you would end up with the following progression:
Initial String: #"Hello world"
Tap one: #"Hello world this is some new text"
Tap Two: #"Hello world this is some new text this is some new text"
Tap Three: #"Hello world this is some new text this is some new text text this is some new text"
If all you are doing is appending text, you might find this a little simpler:
myTextView.text = [myTextView stringByAppendingString:#"suffix\n"];
I found this on UITextView insert text in the textview text. Sadly, I have not found a way to append text directly without a wholesale replacement of the text in the UITextView. It bugs me that the effort involved is proportional to the total length of the existing string and the suffix, rather than just the suffix.
A more efficient way to append text is to use replace() at the end:
extension UITextInput {
func append(_ string : String) {
let endOfDocument = self.endOfDocument
if let atEnd = self.textRange(from: endOfDocument, to: endOfDocument) {
self.replace(atEnd, withText: string)
}
}
}
#Jack Lawrence: Your answer doesn't cover the question completely.
The example below will not scroll neatly while running off the bottom when called every second:
self.consoleView.text = [NSString stringWithFormat:#"%#%#%#", self.consoleView.text, data, #"\n"];
[self.consoleView scrollRangeToVisible:NSMakeRange(self.consoleView.text.length, 0)];
This is caused by setText replacing the original text every time thereby resetting associated contentOffsets etc.
This was possible prior to iOS 7, but since iOS 7 it seems that setText cannot be prevented from exhibiting jumpy behaviour. Appending does not seem to be an option for TextViews in this scenario?
I have 5 cells in a UITableView. Each has a UITextField as a subview, where the user will input data. If I DO use cell reuse, the textfield gets cleared if the cells are scrolled out of view. I don't want to have to deal with this. Is there a way to NOT reuse cells so that I don't have this issue, if so, how?
Is this a bad idea?
I have same feature in one of my apps and I used below code to accomplish that and I never had this kind of problem.
First of all you need to store all your textField value temporary in Array. Make array like this.
arrTemp=[[NSMutableArray alloc]initWithObjects:[NSString stringWithFormat:#""],
[NSString stringWithFormat:#""],
[NSString stringWithFormat:#""],
[NSString stringWithFormat:#""],
[NSString stringWithFormat:#""],
[NSString stringWithFormat:#""],
[NSString stringWithFormat:#""],
[NSString stringWithFormat:#""],
[NSString stringWithFormat:#""],nil];
Then Give all textField tag = indexPath.row;
After that You need to replace textField value in below two methods.
-(BOOL)textFieldShouldReturn:(UITextField *)textField{
[arrTemp replaceObjectAtIndex:textField.tag withObject:textField.text];
}
-(void)textFieldDidEndEditing:(UITextField *)textField{
[arrTemp replaceObjectAtIndex:textField.tag withObject:textField.text];
}
At Last You need to set that value in cellForRowAtIndexPath datasource Method. So that whenever user scroll tableview it set previous value from temp array. Like this.
cell.txtEntry.text = [arrTemp objectAtIndex:indexPath.row];
It might possible I forgot some of the code to paste here. So if you have any problem please let me know.
You can give each cell a unique ReuseIdentifier, maybe by appending the indexPath.row to the name. If you have only 5 cells, this will probably be fine, but you're losing one of the main benefits of a UITableView. In this case, you may want to use a UIScrollView instead.
I would say 5 textview's is a perfect case for not queueing and de-queueing the cells, just create them all in view did load, store in an array and return as requested.
If you open up Apple's Recipes sample application, you will see how Apple uses a xib file to load UITableViewCells.
In the IngredientDetailViewController file:
#property (nonatomic, assign) IBOutlet EditingTableViewCell *editingTableViewCell;
// ...
[[NSBundle mainBundle] loadNibNamed:#"EditingTableViewCell" owner:self options:nil];
// this will cause the IBOutlet to be connected, and you can now use self.editingTableViewCell
Although it looks like they are reusing the cell, you could use the same method to load the 5 cells into 5 separate IBOutlets, and then in cellForRowAtIndexPath, you just return those 5 rather than calling the dequeue method.
Note: you will probably need to store the cells as strong properties (rather than assigning them).
I'm currently struggling with the need to display strikethrough text in many UITableViewCells. Something that written in HTML would looke like
<strike>€99</strike> save 50% => now €49
I don't want to use a UIWebView just for a single line of text, especially that it's used in small UITableViewCells. I know there are reusable cells and all, but I'd like to keep things the more memory-efficient way possible.
So... I'm using NSAttributedStrings, with the help of AliSoftware's UILabel-replacement OHAttributedLabel. The fact that it's only available starting with iOS 4.0 is no problem, as we use all kinds of stuff only 4.0-compatible.
I can manage to create the attributed string, it displays text in the OHAttributedLabel, OK, that's cool. But what I can't achieve is setting the "strikeout", or "strikethrough" attribute.
Basically I go like this:
NSString *price = [NSString stringWithFormat:#"%01.2f €", product.price];
NSString *rate = [NSString stringWithFormat:#" -%01.0f%%", product.reductionRate];
NSMutableAttributedString *s = [NSMutableAttributedString attributedStringWithString:price];
[s addAttribute:NSStrikethroughStyleAttributeName value:[NSNumber numberWithInteger:NSUnderlinePatternSolid | NSUnderlineStyleSingle] range:NSRangeFromString(price)];
[attributedLabel setAttributedText:s];
But here, the three NS* constants are undefined. I've imported CoreText.h, Foundation/NSAttributedString.h, to no avail. I've seen somewhere on the web that
NSStrikethroughStyleAttributeName = #"NSStrikethroughStyleAttributeName", and that NSUnderlinePatternSolid = 0 and NSUnderlineStyleSingle = 1, but hard-coding these values don't give anything.
One thing I got with auto-completion are the equivalent kCT...* constants, but there are kCTUnderlineStyleAttributeName, kCTStrokeWidthAttributeName, ... but no mention of kCTStrikethrough_anything.
What should I do to display that *$|#!# piece of strike-through text ?
With iOS 6 you can use NSStrikethroughStyleAttributeName
[attributedString addAttribute:NSStrikethroughStyleAttributeName value:[NSNumber numberWithInt:NSUnderlineStyleSingle] range:selectedRange];
While it may seem out of place, the numberWithInt value is correct as NSUnderlineStyleSingle.
A simpler approach might be two labels, using the answer to this question - Pixel Width of the text in a UILabel - to strikeout the text in one of the labels.
I have the following code:
static NSString *CellIdentifier = #"Cell";
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] autorelease];
cell.textLabel.text = #"Publisher";
cell.detailTextLabel.text = #"This Is A Very Very Long String";
which results with the following look: (only first table row is relevant)
As it appears, the detail text is overlapping the "Publish" title so both strings are truncated.
What I wish is to have the "Publish" title neverc being truncated as follows:
Is this possible using UITableViewCellStyleValue1? I saw many posts suggesting to create a custom cell but is it really the only way?
Thanks,
Josh
You can try to set adjustsFontSizeToFitWidth property for cell's labels to YES and minimumFontSize property to an appropriate value. If it does not help - it seems you should use custom cells indeed.
I realize some time has passed since this post, so there have probably been updates to this functionality from the SDK. What I've found in Xcode v4.1 is UITableViewCellStyleValue1 now does what you wished. The textLabel.text doesn't truncate.
Using UITableViewCellStyleValue2 will truncate the title. Where the doc suggests
it functions as a heading or caption for the important information in
the more prominent, left-aligned detail text label.