Voice over only reads UILabels and not UIWebview content - ios

I have created UITableViewCell, that contains 2 objects:
UILabel - Used to show title text.
UIWebView- Used to show HTML.
Normally when Voice focus UITableViewCell, it read all added labels without any problem, but in my case, voice over only reads title and not the webview html content, user has to swipe right and left to move to next/previous element to read the content of webview.
My requirement is that when voice focus UITableViewCell, voice should read UILabels and webview content in one go, because as a developer we know its a HTML, but for app user(blind)
doesn't have any idea about it.
Also I want to know that how to disable UIWebview accessibility. I tried by setting isAccessibility to NO, but still Voice Over focus UIWebview.
[self.webview setIsAccessibilityElement:NO];
How to solve this problem?

I have resolved this problem by implementing method "accessibilityLabel" inside table cell view. For webview fetch web view content, convert html into plain text and use it. Don't forget to disable label and webview accessibility.
-(NSString*)accessibilityLabel{
NSString *labelText=nil;
NSMutableString *cellLabelText=[[NSMutableString alloc] init];
//Set label
[cellLabelText appendString:[NSString stringWithFormat:#", %#", self.titleLabel.text]];
//Fetch web view content, convert html into plain text and use it.
NSString *html = [self stringByEvaluatingJavaScriptFromString: #"document.body.innerHTML"];
NSString *plainText=[self convertHTMLIntoPlainText:html];
[cellLabelText appendString:plainText];
labelText=[NSString stringWithString:cellLabelText];
[cellLabelText release];
return labelText;
}
-(NSString *)convertHTMLIntoPlainText:(NSString *)html{
NSScanner *myScanner;
NSString *text = nil;
myScanner = [NSScanner scannerWithString:html];
while ([myScanner isAtEnd] == NO) {
[myScanner scanUpToString:#"<" intoString:NULL] ;
[myScanner scanUpToString:#">" intoString:&text] ;
html = [html stringByReplacingOccurrencesOfString:[NSString stringWithFormat:#"%#>", text] withString:#""];
}
//
html = [html stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
return html;
}

How about:
[self.webview setAccessibilityElementHidden:YES]
Then set whatever accessibility label you like on the cell with the accessibilityLabel property.

Related

Cell with NSAttributedString makes the scrolling of UITableView slow

I have a table view that contains multiple kinds of cells. One of them is a cell with a TextView and in this text view, I have to render an NSAttributedString from data. This has to be done on the main Thread according to Apple documentation:
The HTML importer should not be called from a background thread (that is, the options dictionary includes NSDocumentTypeDocumentAttribute with a value of NSHTMLTextDocumentType). It will try to synchronize with the main thread, fail, and time out. Calling it from the main thread works (but can still time out if the HTML contains references to external resources, which should be avoided at all costs). The HTML import mechanism is meant for implementing something like markdown (that is, text styles, colors, and so on), not for general HTML import.
but rendering in this way will make lags on the scrolling of the table view and also will mess with auto layout. This is my code inside my cell.
dispatch_async(dispatch_get_main_queue(), ^{
NSString* htmlString = [NSString stringWithFormat:#"<div style=\"font-family:%#; font-size:%dpx; color:#08080d;\">%#</div>",fontNameBase, 16,txt];
htmlString = [Utility replaceHtmlCodeEntities:htmlString];
NSData* tempData = [htmlString dataUsingEncoding:NSUnicodeStringEncoding];
NSAttributedString *attributedString = [[NSAttributedString alloc] initWithData:tempData options:#{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType} documentAttributes:nil error:nil];
self.textViewMsg.attributedText = txt;
});
I scroll my tableView like this:
-(void)reloadAndScroll{
[self.tableChat reloadData];
long lastRowNumber = [_tableChat numberOfRowsInSection:0] - 1;
if (lastRowNumber > 0) {
NSIndexPath* indexPath = [NSIndexPath indexPathForRow:lastRowNumber inSection:0];
[_tableChat scrollToRowAtIndexPath:indexPath
atScrollPosition:UITableViewScrollPositionBottom animated:NO];
}
}
Are there any other ways to create an Attributed string without these problems?
I think u have to create the Attributed String in your Model class, So that table view cell for row method does not create a new Attributed string on scrolling,Hope It well help you out, Thanks
+(AttributedModel *)methodToGetAttributedDetail :(NSString *)txt {
AttributedModel *objModel = [[AttributedModel alloc] init];
NSString* htmlString = [NSString stringWithFormat:#"<div style=\"font-family:%#; font-size:%dpx; color:#08080d;\">%#</div>",fontNameBase, 16,txt];
htmlString = [Utility replaceHtmlCodeEntities:htmlString];
NSData* tempData = [htmlString dataUsingEncoding:NSUnicodeStringEncoding];
NSAttributedString *attributedString = [[NSAttributedString alloc] initWithData:tempData options:#{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType} documentAttributes:nil error:nil];
objModel.attributedString = attributedString;
return objModel;
}
Use this model value in CellforRow Method of table view

iOS: The proper way to display Images and long texts with scroll functionality

I'm developing an app for a news website, i'm displaying the news articles using UITableView where each cell is an article title, when a user clicks on a cell (i.e an article), another view opens (using segue), now in this view i want to put the following:
The article's Image at the top.
The article's date under the image.
The article's description under the date. (Which could be very long)
The ability for the user to scroll the entire view. (not only the description)
NOTE: I have tried so many ways, i can't seem to know the proper way to implement this structure.
The modern solution is actually relatively simple: compose the whole thing as an attributed string and put it into a UITextView. The text view will automatically deal with the fact that the description may be very long, that all content should scroll together, etc.
E.g.
NSAttributedString *imageString = [NSAttributedString attributedStringWithAttachment:
[[NSTextAttachment new] setImage:[UIImage imageNamed:#"whatever.png"]]];
... and use the natural means for composition of attributed strings and for setting things like font and colour on your other bits of text. Then just textView.attributedString = compoundString;.
Elaborated example:
- (void)setStory:(Story *)story
{
NSAttributedString *image = [story imageString];
NSAttributedString *date = [story dateString];
NSAttributedString *body = [story bodyString];
NSMutableAttributedString *wholeStory = [NSMutableAttributedString new];
// TODO: can you be sure image, date and body are all non-nil?
NSArray *allComponents = #[image, date, body];
for(NSAttributedString *component in allComponents)
{
[wholeStory appendAttributedString:component];
if(component != [allComponents lastObject])
[[wholeStory mutableString] appendString:#"\n\n"];
}
self.textView.attributedString = wholeStory;
}
... elsewhere, in the Story object ...
- (UIImage *)image
{
// ...something...
}
- (NSString *)dateText
{
// ...something, probably using NSDateFormatter unless it's returned
// from a server or wherever already formatted...
}
- (NSString *)bodyText
{
// ... something ...
}
- (NSAttributedString *)imageString
{
return [NSAttributedString attributedStringWithAttachment:
[[NSTextAttachment new] setImage:[self image]]];
}
- (NSAttributedString *)dateString
{
return [[NSAttributedString alloc]
initWithString:[self dateText]
attributes:
#{
NSFontAttributeName: [UIFont preferredFontForTextStyle: UIFontTextStyleSubheadline],
... etc ...
}];
}
- (NSAttributedString *)bodyString
{
return [[NSAttributedString alloc]
initWithString:[self bodyText]
attributes:
#{
NSFontAttributeName: [UIFont preferredFontForTextStyle: UIFontTextStyleBody],
... etc ...
}];
}
Check out the NSAttributedString UIKit Additions documentation for lists of the various attributes you can set other than NSFontAttributeName. Note that I've gone with the iOS 7+ way of asking for fonts by purpose rather than a specific size or font. That means that users who have turned up their default font size will get larger text in your app.
I have created a pod to programmatically add constraints. There is a special category for scrollViews, because they are so complicated to use with auto layout.
Here is the link to the project
There is an example app you can take a look at, but the things you would have to do would be
initialize your views (the image, date label and description label).
add the scrollView
add the subviews of the scrollView
UIScrollView *scrollView = [[UIScrollView alloc] init];
[self.view addSubview:scrollView];
[scrollView addConstraintsToFillHorizontal];
[scrollView addConstraintsToFillVertical];
[scrollView addConstraintsToAlignVerticalAllViews:#[image, dateLabel, descriptionLabel]];
This should be pretty simple to implement, but if you need more help, just let me know and I could provide you with some more sample code.
Good luck with your project!
Another way would be to display each article as a HTML string in a UIWebView.
NSURL *url = [NSURL URLWithString:self.articleController.url];
NSString *html = [NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:NULL];
[self.articleView.webView loadHTMLString:html baseURL:baseURL];

Auto focus text field in UIWebview

I am loading a webview form in my iOS app and I want to autofocus a textfield on the form. I tried
NSString *focus = [NSString stringWithFormat:#"document.getElementsByName('j_captcha')[0].focus()"];
[self.webView stringByEvaluatingJavaScriptFromString: focus];
But that doesnt seem to work. "j_captcha" is the name of the textfield. How can I achieve this?
This did the trick for me
NSString *evalStr = [NSString stringWithFormat:#"setTimeout( function(){document.getElementsByName('j_captcha')[0].focus();},1000);"];
[webView stringByEvaluatingJavaScriptFromString:evalStr];
This post helped - https://stackoverflow.com/a/14268931/653978

Change size of text in UITextView based on content of NSString

I am trying to load a UITextView with content from instances of a NSManagedObject subclass (verses in a Bible reader app).
My UITextView is loaded by iterating through the verses in a selected chapter and appending each consecutive verse.
NSArray *selectedVerses = [[Store sharedStore] versesForBookName:selectedBook
ChapterNumber:selectedChapterNum];
displayString = #"";
for (Verse *v in selectedVerses) {
NSMutableString *addedString =
[NSMutableString stringWithFormat:#"%d %#", [v versenum], [v verse]];
displayString = [NSMutableString stringWithFormat:#"%# %#", addedString, displayString];
}
NSString *title = [NSString stringWithFormat:#"%# %#", selectedBook, selectedChapter];
[self setTitle:title];
[[self readerTextView] setNeedsDisplay];
[[self readerTextView] setText:displayString];
The above code generates the correct view, but only allows for one size of text for the entire UITextView.
I would like to have the verse number that precedes each verse to be a smaller size font than its verse, but have not found a way to make it work. I've been reading through the documentation, and it seems that this should be possible with TextKit and CoreText through the use of attributed strings, but I can't seem to get this to compile.
I do not want to load the view as a UIWebView.
Any suggestions for this are greatly appreciated.
You're looking for NSAttributedString and NSMutableAttributedString. You should read Introduction to Attributed String Programming Guide. They're generally like normal strings, but additionally contain attributes with ranges to which they apply. One more method that would be helpful to you is:
[self readerTextView].attributedText = yourAttributedString;
If you have some specific problems with attributed strings, please post your code.

Set dynamic height of webview depending on the content on an iPhone

I want set dynamic height for webview depending on the dynamic text. I've tried
[my_webview sizeThatFits:CGSizeZero];
But it didn't work for me. I want to set webview height dynamically.
See my answer to a similar question. The trick is to set the frame of the webView to a minimal height prior to sending -sizeThatFits:.
Set up your web view as follows:
- (void)webViewSettings {
NSString *htmlString = #"Your HTML String";
NSString* descHtmlString = [NSString stringWithFormat: #"<html><meta name=\"viewport\" content=\"width=300, user-scalable=yes\" /><div style='width:300px' id='ContentDiv'><font face=\"Arial\" size=2.5 color='#702f70'>%#</font></div></html>", htmlString];
descHtmlString = [descHtmlString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
[self.webView loadHTMLString:descHtmlString baseURL:[NSURL URLWithString:#""]];
}
Then implemented UIWebViewDelegate in your interface file and the following method in the implementation file:
- (void)webViewDidFinishLoad:(UIWebView *)webView {
NSString *contentHeight = [self.descriptionWeb stringByEvaluatingJavaScriptFromString:#"document.getElementById('ContentDiv').offsetHeight"];
self.descriptionWeb.frame = CGRectMake(10,webView.frame.origin.y, 300, [contentHeight floatValue]);
}

Resources