UIAccessibility VoiceOver announces wrong page number for UIScrollView - iphone

I am trying to make an existing app as accessible as possible for voice over.
Currently, I have a uiviewcontroller thats basically a paging photo view with a uipagecontrol below the uiscrollView (tourScrollView) that indicates the current image/page being viewed.
here's the code that calculate's the current page:
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
CGFloat pageWidth = scrollView.frame.size.width;
self.tourScrollView.isAccessibilityElement = NO;
scrollView.isAccessibilityElement = NO;
int currentPage = floor((scrollView.contentOffset.x - pageWidth / 2) / pageWidth) + 1;
pageControl.currentPage = currentPage;
}
the page calculation code works perfect.
There are a total of 5 images being shown.
With voice over enabled, when the scroll view scrolls, instead of going
page 1 of 5
page 2 of 5
page 3 of 5
page 4 of 5
page 5 of 5
it goes like this.
page 1 of 6
page 2 of 6
page 3 of 6
page 5 of 6
page 6 of 6
Here's the code where the images are added to the scrollView
-(void)addImagesToScrollview{
NSArray *welcomeImages = [[NSArray alloc] initWithObjects:[UIImage imageNamed:#"img-01.png"],
[UIImage imageNamed:#"img-02.png"],
[UIImage imageNamed:#"img-03.png"],
[UIImage imageNamed:#"img-04.png"],
[UIImage imageNamed:#"img-05.png"],nil];
CGRect scrollViewFrame = tourScrollView.frame;
CGFloat scrollViewWidth = scrollViewFrame.size.width;
CGFloat scrollViewHeight = scrollViewFrame.size.height;
CGFloat imageX;
for (int i = 0; i<[welcomeImages count]; i++) {
int index = i;
imageX = (scrollViewWidth*index) + (scrollViewWidth - IMAGE_WIDTH)/2.0;
CGRect boarderViewRect = CGRectMake(imageX, 20.0f, IMAGE_WIDTH, IMAGE_HEIGHT);
UIView *whiteBorderView = [[UIView alloc] initWithFrame:boarderViewRect];
whiteBorderView.backgroundColor = [UIColor whiteColor];
UIImageView *imageView = [[UIImageView alloc]initWithImage:[welcomeImages objectAtIndex:i]];
CGRect imageRect = CGRectInset(boarderViewRect, IMAGE_INSET, IMAGE_INSET);
imageView.frame = imageRect;
CGRect descriptionRect = CGRectMake((scrollViewWidth*index) + 20.0f, imageRect.origin.y + imageRect.size.height+10, 280, 90);
CGSize maximumLabelSize = CGSizeMake(descriptionRect.size.width,120);
descriptionRect.size = [[self descriptionForIndex:i] sizeWithFont:[UIFont systemFontOfSize:16.0] constrainedToSize:maximumLabelSize lineBreakMode:UILineBreakModeTailTruncation];
UILabel *imageDescription = [[UILabel alloc] initWithFrame:descriptionRect];
imageDescription.text = [NSString stringWithFormat:#"%#",[self descriptionForIndex:i]];
imageDescription.numberOfLines = 0;
imageDescription.backgroundColor = [UIColor clearColor];
imageDescription.font = [UIFont systemFontOfSize:16.0];
imageDescription.textColor = [UIColor colorWithRed:(119.0/255.0) green:(119.0/255.0) blue:(119.0/255.0) alpha:1.0];
imageDescription.textAlignment = UITextAlignmentCenter;
imageDescription.shadowColor = [UIColor whiteColor];
imageDescription.shadowOffset = CGSizeMake(0,1);
[tourScrollView addSubview:whiteBorderView];
[tourScrollView addSubview:imageView];
[tourScrollView addSubview:imageDescription];
if (i == [welcomeImages count]-1) {
tourScrollView.contentSize = CGSizeMake(imageView.frame.origin.x + scrollViewWidth -((scrollViewWidth - IMAGE_WIDTH)/2.0), scrollViewHeight);
}
}
}
I'd appreciate if someone points me to the right direction to make voice over say the correct page numbers.
update: Enabling/disabling pagingEnabled makes no difference. I think voiceOver overrides the paging calculations I do based on the scrollview size.

Here's what fixed it:
removed the commented code, and added a line for the content size outside the for loop
-(void)addImagesToScrollview{
NSArray *welcomeImages = [[NSArray alloc] initWithObjects:[UIImage imageNamed:#"img-01-welcome.png"],
[UIImage imageNamed:#"img-02-welcome.png"],
[UIImage imageNamed:#"img-03-welcome.png"],
[UIImage imageNamed:#"img-04-welcome.png"],
[UIImage imageNamed:#"img-05-welcome.png"],nil];
CGRect scrollViewFrame = tourScrollView.frame;
CGFloat scrollViewWidth = scrollViewFrame.size.width;
CGFloat scrollViewHeight = scrollViewFrame.size.height;
CGFloat imageX;
for (int i = 0; i<[welcomeImages count]; i++) {
int index = i;
imageX = (scrollViewWidth*index) + (scrollViewWidth - IMAGE_WIDTH)/2.0;
CGRect boarderViewRect = CGRectMake(imageX, 20.0f, IMAGE_WIDTH, IMAGE_HEIGHT);
UIView *whiteBorderView = [[UIView alloc] initWithFrame:boarderViewRect];
whiteBorderView.backgroundColor = [UIColor whiteColor];
UIImageView *imageView = [[UIImageView alloc]initWithImage:[welcomeImages objectAtIndex:i]];
CGRect imageRect = CGRectInset(boarderViewRect, IMAGE_INSET, IMAGE_INSET);
imageView.frame = imageRect;
CGRect descriptionRect = CGRectMake((scrollViewWidth*index) + 20.0f, imageRect.origin.y + imageRect.size.height+10, 280, 90);
CGSize maximumLabelSize = CGSizeMake(descriptionRect.size.width,120);
descriptionRect.size = [[self descriptionForIndex:i] sizeWithFont:[UIFont systemFontOfSize:16.0] constrainedToSize:maximumLabelSize lineBreakMode:UILineBreakModeTailTruncation];
UILabel *imageDescription = [[UILabel alloc] initWithFrame:descriptionRect];
imageDescription.text = [NSString stringWithFormat:#"%#",[self descriptionForIndex:i]];
imageDescription.numberOfLines = 0;
imageDescription.backgroundColor = [UIColor clearColor];
imageDescription.font = [UIFont systemFontOfSize:16.0];
imageDescription.textColor = [UIColor colorWithRed:(119.0/255.0) green:(119.0/255.0) blue:(119.0/255.0) alpha:1.0];
imageDescription.textAlignment = UITextAlignmentCenter;
imageDescription.shadowColor = [UIColor whiteColor];
imageDescription.shadowOffset = CGSizeMake(0,1);
[tourScrollView addSubview:whiteBorderView];
[tourScrollView addSubview:imageView];
[tourScrollView addSubview:imageDescription];
// if (i == [welcomeImages count]-1) {
// tourScrollView.contentSize = CGSizeMake(imageView.frame.origin.x + scrollViewWidth -((scrollViewWidth - IMAGE_WIDTH)/2.0), scrollViewHeight);
// }
}
tourScrollView.contentSize = CGSizeMake(320.0*[welcomeImages count], scrollViewHeight);
}
I am still not sure why VO would mess up the page numbers. The scrollview behavior, before and after the fix is still the same (bouncing and paging work identical).
will update the answer if I get to know more about this issue.

One easy option is to conform to your UIScrollViewDelegate to UIScrollViewAccessibilityDelegate and return the desired string.
For example:
extension MyScrollViewDelegate: UIScrollViewAccessibilityDelegate {
func accessibilityScrollStatus(for scrollView: UIScrollView) -> String? {
"\(self.currentPage) of \(self.pageCount)"
}
}

Related

How can I add a white space between image?

I write a code to loop for creating multiple image on UIImageView inside scrollview. i did something like this:
UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(38, 9, 90, 280)];
int numberOfImages = 9;
CGFloat currentY = 0.5f;
for (int i=1; i <= numberOfImages; i++) {
NSString *imageName = [NSString stringWithFormat:#"img0%d.jpg",i];
UIImage *image = [UIImage imageNamed:imageName];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
imageView.frame = CGRectMake(2, 15, 87, imageView.frame.size.height - 20);
CGRect rect = imageView.frame;
rect.origin.y = currentY;
imageView.frame = rect;
currentY += imageView.frame.size.height;
[scrollView addSubview:imageView];
}
scrollView.contentSize = CGSizeMake(87,currentY);
[self.view addSubview:scrollView];
Now, i need to add a space between each image, how can i do that?
Add a bit more to currentY?
currentY += imageView.frame.size.height + 12.0f;

PageControl Issue in iphone

I have a gridview when i click on any image i send current index of that gridview so i can see that image. and I am loading images from doucment.
below is my viewDidload code.
but what my problem is. when i click any gridview item . let say its index is 4. and i set it here in currentpage=4. so when i open this page. it shows me 4th image. but my page controller current page is 4 but i can see my image which was at index 1.
- (void)viewDidLoad {
[super viewDidLoad];
pageControlBeingUsed = NO;
UIImageView *subview;
//NSArray *colors = [NSArray arrayWithObjects:[UIColor redColor], [UIColor greenColor], [UIColor orangeColor],[UIColor blueColor], nil];
for (int i = 0; i < (NSInteger)totalImagesInGrid; i++) {
CGRect frame;
frame.origin.x = self.scrollView.frame.size.width * i;
frame.origin.y = 0;
frame.size = self.scrollView.frame.size;
subview = [[UIImageView alloc] initWithFrame:frame];
//subview.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:[tableDataArray objectAtIndex:i]]];
NSString *name = [tableDataArray objectAtIndex:(NSUInteger)i];
NSFileHandle* myFileHandle = [NSFileHandle fileHandleForReadingAtPath:name];
UIImage* loadedImage = [UIImage imageWithData:[myFileHandle readDataToEndOfFile]];
subview.image = loadedImage;
[self.scrollView addSubview:subview];
[subview release];
}
//float count = [totalImagesInGrid floatValue];
self.scrollView.contentSize = CGSizeMake(self.scrollView.frame.size.width * 13, self.scrollView.frame.size.height);
self.pageControl.currentPage = (NSInteger)currentImage;
NSLog(#"currentPage %d",(NSInteger)currentImage);
self.pageControl.numberOfPages = (NSInteger)totalImagesInGrid;
NSLog(#"(NSInteger)totalImagesInGrid %d",(NSInteger)totalImagesInGrid);
}
- (void)scrollViewDidScroll:(UIScrollView *)sender {
if (!pageControlBeingUsed) {
// Switch the indicator when more than 50% of the previous/next page is visible
CGFloat pageWidth = self.scrollView.frame.size.width;
int page = floor((self.scrollView.contentOffset.x - pageWidth / 2) / pageWidth) + 1;
self.pageControl.currentPage = (NSInteger)currentImage + page;
NSLog(#"Page %d",page);
}
NSLog(#"scrollViewDidScroll");
}
- (IBAction)changePage {
// Update the scroll view to the appropriate page
CGRect frame;
frame.origin.x = self.scrollView.frame.size.width * self.pageControl.currentPage;
frame.origin.y = 0;
frame.size = self.scrollView.frame.size;
[self.scrollView scrollRectToVisible:frame animated:YES];
pageControlBeingUsed = YES;
}
this is my gridview and i m click on (1,1) image.
And this is my page control view. but thats not the image i have selected . this is (0,1) image but see at page control it is on index 2.
set page index with selectedIndex of gridview for example see bellow...
- (void) gridView:(UIGridView *)grid didSelectRowAt:(int)rowIndex AndColumnAt:(int)colIndex{
///set Image with index of colIndex..
int selectedIndex = (rowIndex*4)+colIndex;
NSLog(#"\n Selected Image Index is %d",selectedIndex);
}
and in SecondView Class's viewDidLoad: just call your secondView class method changePage at last of the method like bellow
- (void)viewDidLoad {
////another your code
[self changePage]
}
i hope this help you..

how to programmatically draw border and remove it after words around UIImageview?

Please read my question before marking it as duplicate or repeat question...
I have one scroleView in which I put some images in tabular form.
When user click one of it the next view controller is shown and the
clicked image's uiview get green border.
And when user navigate back to this view the clicked image is shown
with green border. all this worked fine
But the problem starts when user clicks other images : the previously clicked image doesn't get back to normal, ie, its border stays there even if I put its width to 0.0 and color to clearColor
Please guide me how to remove those borders
My code is as below:
for (int row = 0; row < r; ++row)
{
for (int col = 0; col < 2; ++col)
{
int index = (row * 2) + col;
if(index < [tempArr count])
{
CGRect frame = CGRectMake(10+col*(10+145),10+row*(5+100),145, 100);
UIView *fr = [[UIView alloc] initWithFrame:frame];
CGRect imgFrame = CGRectMake(0, 0, 145, 100);
UIImageView *imgView = [[UIImageView alloc]initWithFrame:imgFrame];
imgView.image = [UIImage imageNamed:[[tempArr objectAtIndex:index]valueForKey:#"add"]];
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc]initWithTarget:self action:#selector(tapAction:)];
fr.layer.borderWidth = 0.0f;
fr.layer.borderColor = [UIColor greenColor].CGColor;
if(selctedFrame == index)//Here i put border
{
fr.layer.borderWidth = 2.0f;
fr.layer.borderColor = [UIColor greenColor].CGColor;
}
else //here i remove them
{
fr.layer.borderWidth = 0.0f;
fr.layer.borderColor = [UIColor clearColor].CGColor;
}
tapGesture.numberOfTapsRequired = 1;
tapGesture.numberOfTouchesRequired = 1;
[fr addGestureRecognizer:tapGesture];
[fr addSubview:imgView];
fr.tag = index;
[self.scrollDisplay addSubview:fr];
[self.scrollDisplay bringSubviewToFront:fr];
}
}
}
[self.view addSubview:self.scrollDisplay];
This method is called in viewWillAppear:animated: method
Edit
after some navigation forth and back
New Answer- I think the problem is that you're adding new views again and again. Instead of doing UIView *fr = [[UIView alloc] initWithFrame:frame];, find the already existing view as: UIView *fr = [self.scrollDisplay viewWithTag:index]; and make changes to it. In effect, new imageviews are being added over the old ones which is highly inefficient, besides causing the mentioned issue. I'm assuming you've already added the views to scrollDisplay. You also shouldn't create new imgView objects again. Set tags for them that make them unique and easy to get. For eg, set the tag 999 for each imgView and retrieve it as:UIImageView *imgView = [fr viewWithTag:999]; Also, get rid of [fr addSubview:imgView];, [self.scrollDisplay addSubview:fr]; and [self.view addSubview:self.scrollDisplay]; towards the end. So your code should look like this:
for (int row = 0; row < r; ++row)
{
for (int col = 0; col < 2; ++col)
{
int index = (row * 2) + col;
if(index < [tempArr count])
{
CGRect frame = CGRectMake(10+col*(10+145),10+row*(5+100),145, 100);
UIView *fr = [self. scrollDisplay viewWithTag:index];
CGRect imgFrame = CGRectMake(0, 0, 145, 100);
UIImageView *imgView = [fr viewWithTag:999];
//imgView.image = [UIImage imageNamed:[[tempArr objectAtIndex:index]valueForKey:#"add"]]; //<--You've already set the image before so you don't need this
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc]initWithTarget:self action:#selector(tapAction:)];
fr.layer.borderWidth = 0.0f;
fr.layer.borderColor = [UIColor greenColor].CGColor;
if(selctedFrame == index)//Here i put border
{
fr.layer.borderWidth = 2.0f;
fr.layer.borderColor = [UIColor greenColor].CGColor;
}
else //here i remove them
{
fr.layer.borderWidth = 0.0f;
fr.layer.borderColor = [UIColor clearColor].CGColor;
}
tapGesture.numberOfTapsRequired = 1;
tapGesture.numberOfTouchesRequired = 1;
//[fr addGestureRecognizer:tapGesture]; //<-- Not needed if you've already done this
//[fr addSubview:imgView];//<-- Not needed
fr.tag = index;
//[self.scrollDisplay addSubview:fr];//<-- Not needed
[self.scrollDisplay bringSubviewToFront:fr];//<-- probably not needed
}
}
}
//[self.view addSubview:self.scrollDisplay];//<-- Not needed
i just need to do is to set the border color to the background color of the view. any other options did nothing the border is not been hidden through any thing else the only work around i got is this

iphone: how to add text above and below the image in the scrollvew?

I would like to add a page number above the image such as "1 of 50" and description of the image below the image in the scrollview.
I have looked at this LINK but still couldn't figure out how to make it happen.
here is my sample code of the images scrollview. Im trying to find a sample that can add text and scroll with the images
NSUInteger i;
for (i = 1; i <= kNumImages; i++)
{
NSString *imageName = [NSString stringWithFormat:#"images%d.jpg", i];
UIImage *image = [UIImage imageNamed:imageName];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
// setup each frame to a default height and width, it will be properly placed when we call "updateScrollList"
CGRect rect = imageView.frame;
rect.size.height = kScrollObjHeight;
rect.size.width = kScrollObjWidth;
imageView.frame = rect;
imageView.tag = i; // tag our images for later use when we place them in serial fashion
[scrollView1 addSubview:imageView];
[imageView release];
}
UPDATE:
const CGFloat kScrollObjHeight = 320;
const CGFloat kScrollObjWidth = 280.0;
const NSUInteger kNumImages = 50;
- (void)layoutScrollImages
{
UIImageView *view = nil;
NSArray *subviews = [scrollView1 subviews];
// reposition all image subviews in a horizontal serial fashion
CGFloat curXLoc = 0;
for (view in subviews)
{
if ([view isKindOfClass:[UIImageView class]] && view.tag > 0)
{
CGRect frame = view.frame;
frame.origin = CGPointMake(curXLoc, 0);
view.frame = frame;
curXLoc += (kScrollObjWidth);
}
}
- (void)viewDidLoad {
self.view.backgroundColor = [UIColor viewFlipsideBackgroundColor];
// 1. setup the scrollview for multiple images and add it to the view controller
//
// note: the following can be done in Interface Builder, but we show this in code for clarity
[scrollView1 setBackgroundColor:[UIColor blackColor]];
[scrollView1 setCanCancelContentTouches:NO];
scrollView1.indicatorStyle = UIScrollViewIndicatorStyleWhite;
scrollView1.clipsToBounds = YES; // default is NO, we want to restrict drawing within our scrollview
scrollView1.scrollEnabled = YES;
// pagingEnabled property default is NO, if set the scroller will stop or snap at each photo
// if you want free-flowing scroll, don't set this property.
scrollView1.pagingEnabled = YES;
// load all the images from our bundle and add them to the scroll view
NSUInteger i;
for (i = 1; i <= kNumImages; i++)
{
NSString *imageName = [NSString stringWithFormat:#"creative%d.jpg", i];
UIImage *image = [UIImage imageNamed:imageName];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
// setup each frame to a default height and width, it will be properly placed when we call "updateScrollList"
CGRect rect = imageView.frame;
rect.size.height = kScrollObjHeight;
rect.size.width = kScrollObjWidth;
imageView.frame = rect;
imageView.tag = i; // tag our images for later use when we place them in serial fashion
[scrollView1 addSubview:imageView];
[imageView release];
}
[self layoutScrollImages];
I wanted to put this but unable to find the correct position or right offset to display at the top
UILabel * topLabel = [[UILabel alloc] init];
topLabel.text = [NSString stringWithFormat:#"%d of %d", i, kNumImages];
rect.origin.x = offset;
rect.size.height = 30; // however large you need the label to be
topLabel.frame = rect;
offset += 30;
I would think something like this would work:
float offset = 0;
for (NSUInteger i = 1; i <= kNumImages; i++)
{
// load up the image
NSString *imageName = [NSString stringWithFormat:#"images%d.jpg", i];
UIImage *image = [UIImage imageNamed:imageName];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
// image.size is important here and used to determine placement
CGRect rect = imageView.frame;
rect.size = image.size;
// create top label, just basic will need to configure other settings like font
UILabel * topLabel = [[UILabel alloc] init];
topLabel.text = [NSString stringWithFormat:#"%d of %d", i, kNumImages];
rect.origin.x = offset;
rect.size.height = 30; // however large you need the label to be
topLabel.frame = rect;
offset += 30; // adding the label height
// set image frame since we now know the location below top label
rect.size = image.size;
rect.origin.x += offset;
imageView.frame = rect;
imageView.tag = i;
offset += image.size.height; // adding image height
// add bottom label below image
UILabel * bottomLabel = [[UILabel alloc] init];
bottomLabel.text = imageName; // just a sample description
rect.origin.x += offset;
rect.size.height = 30; // however large you need the label to be
bottomLabel.frame = rect;
offset += 30; // adding the label height
[scrollView1 addSubview:topLabel];
[scrollView1 addSubview:imageView];
[scrollView1 addSubview:bottomLabel];
[imageView release];
[topLabel release];
[bottomLabel release];
offset += 20; // arbitrary spacing between images
}

Set UIImageView Size?

i have following problem: i generate subviews UIView in an UIScrollView including UIImageViews.
NSArray *bilder = [[NSArray alloc] initWithObjects:#"lol.jpg", #"lol2.jpg", nil];
NSArray *added = [[NSMutableArray alloc] init];
UIImageView *tmpView;
for (NSString *name in bilder) {
UIImage *image = [UIImage imageNamed:name];
tmpView = [[UIImageView alloc] initWithImage:image];
tmpView.contentMode = UIViewContentModeScaleAspectFit;
tmpView.frame = CGRectMake(0, 0, 300, 300);
[added addObject:tmpView];
[tmpView release];
}
CGSize framy = mainFrame.frame.size;
NSUInteger x = 0;
for (UIView *view in added) {
[mainFrame addSubview:view];
view.frame = CGRectMake(framy.height * x++, 0, framy.height, framy.width);
}
mainFrame.scrollEnabled = YES;
mainFrame.pagingEnabled = YES;
mainFrame.contentSize = CGSizeMake(framy.height * [added count], framy.width);
mainFrame.backgroundColor = [UIColor blackColor];
i get image file names out of an array. now i want to resize the imageview to a specific size, but it won't work. any advice?
thanks + regards
UIImage lacks the setSize: method of NSImage, but this post seems to add a scaleToSize: method using a category on UIImage.
Change tmpView.frame to use a new CGRect:
tmpView.frame = CGRectMake(tmpView.frame.origin.x,
tmpView.frame.origin.y,
newWidth,
newHeight);
What I see is:
view.frame = CGRectMake(framy.height * x++, 0, framy.height, framy.width);
But if you look at CGRectMake...
Declaration: CGRect CGRectMake (
CGFloat x,
CGFloat y,
CGFloat width,
CGFloat height
);
You are setting the X value, not the Y value. I expect, based on your later call to:
mainFrame.contentSize = CGSizeMake(framy.height * [added count], framy.width);
that you intend to make the these images appear on top of each other, not side by side.
Suggest:
view.frame = CGRectMake(framy.height * x++, 0, framy.height, framy.width);
to
view.frame = CGRectMake(0,framy.height * x++, framy.height, framy.width);