We have a login screen with a UILabel hidden initially to represent a message when the user logs out of the app.
When VoiceOver is turned on in iOS and the user tries to log out from the app, the voice over should ideally read out the logout message label. Instead, it reads out the password text field of the login screen.
The action of the log out button has the below implementation code.
let loginStoryboard = UIStoryboard(name: "Login", bundle: nil)
let loginViewController = loginStoryboard.instantiateInitialViewController() as! LoginViewController
loginViewController.modalPresentationStyle = UIModalPresentationStyle.CurrentContext
loginViewController.logOut = true
self.presentViewController(loginViewController, animated: true, completion:nil)
The logout indicator is set to display the logout message label.
LoginViewController viewDidLoad code.
if(!logOut){
self.logOutMsg.hidden = true
}else{
self.logOutMsg.text = NSLocalizedString("LoggedOutMsg", comment: "Logged out message")
self.logOutMsg.hidden = false
}
The login screen fields are accessibility enabled in story board.
The behavior is inconsistent: sometimes the logout message label is read and sometimes it reads out the password text field.
Whenever VoiceOver reads the password text field, I can see an error in the console log.
|error| Could not find <UIWindow: 0x124d13b10; frame = (0 0; 768 1024); gestureRecognizers = <NSArray: 0x174241140>; layer = <UIWindowLayer: 0x1742319c0>> in a list of sorted view [parent: <CaseworkerApp.AppDelegate: 0x124e008e0>] siblings (
"<UILabel: 0x124d06cf0; frame = (132 1; 300 18); text = 'You are logged out of IBM...'; opaque = NO; autoresize = RM+BM; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x1742921b0>>",
"<CaseworkerApp.LoginTextField: 0x124da4890; baseClass = UITextField; frame = (80 37; 330 50); text = ''; clipsToBounds = YES; opaque = NO; autoresize = RM+BM; gestureRecognizers = <NSArray: 0x1704551e0>; layer = <CALayer: 0x175033de0>>",
"<CaseworkerApp.LoginTextField: 0x124d9bd50; baseClass = UITextField; frame = (80 110; 330 50); text = ''; clipsToBounds = YES; opaque = NO; autoresize = RM+BM; tag = 1; gestureRecognizers = <NSArray: 0x17044dfb0>; layer = <CALayer: 0x175227ce0>>",
"<UIButton: 0x124d52900; frame = (80 183; 330 50); autoresize = RM+BM; layer = <CALayer: 0x175039ae0>>"
). If this happened right around a screen change, it might be okay, but otherwise this is probably a bug.
2015-08-10 16:46:50.108 CaseworkerApp[2217:479225] |error| Could not find <UIWindow: 0x124d13b10; frame = (0 0; 768 1024); gestureRecognizers = <NSArray: 0x174241140>; layer = <UIWindowLayer: 0x1742319c0>> in a list of sorted view [parent: <CaseworkerApp.AppDelegate: 0x124e008e0>] siblings (
"<UILabel: 0x124d06cf0; frame = (132 1; 300 18); text = 'You are logged out of IBM...'; opaque = NO; autoresize = RM+BM; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x1742921b0>>",
"<CaseworkerApp.LoginTextField: 0x124da4890; baseClass = UITextField; frame = (80 37; 330 50); text = ''; clipsToBounds = YES; opaque = NO; autoresize = RM+BM; gestureRecognizers = <NSArray: 0x1704551e0>; layer = <CALayer: 0x175033de0>>",
"<CaseworkerApp.LoginTextField: 0x124d9bd50; baseClass = UITextField; frame = (80 110; 330 50); text = ''; clipsToBounds = YES; opaque = NO; autoresize = RM+BM; tag = 1; gestureRecognizers = <NSArray: 0x17044dfb0>; layer = <CALayer: 0x175227ce0>>",
"<UIButton: 0x124d52900; frame = (80 183; 330 50); autoresize = RM+BM; layer = <CALayer: 0x175039ae0>>"
).
If this happened right around a screen change, it might be okay, but otherwise this is probably a bug.
Any help please to resolve this?
When a view is presented, VoiceOver starts reading from the first element in the accessibility tree. There are possibly two solutions.
First, you can modify the order.
Change order of read items with VoiceOver
Secondly, you can make VoiceOver to focus on a particular element when a view changes by posting ScreenChanged Notification from UIAccessibility indicating which element VoiceOver should focuss.
UIAccessibility.post(notification:.screenChanged, argument:elementToBeFocussed)
Read more information from the documentation.
UIAccessibility.post: https://developer.apple.com/documentation/uikit/uiaccessibility/1615194-post
UIAccessibility.Notification: https://developer.apple.com/documentation/uikit/uiaccessibility/notification
screenChanged: https://developer.apple.com/documentation/uikit/uiaccessibility/notification/1620198-screenchanged
Related
I use transitionFromView switch two UIView ,But there is somethine wrong with it , When I transition the view to second UIView ,it work ok, then I transition the view back The error is happen(the location of first UIView is wrong)
What happen?
self.primaryView.hidden = !self.primaryView.hidden
self.secondaryView.hidden = !self.secondaryView.hidden
println("\(self.primaryView)")
UIView.transitionFromView(displayingPrimary ? self.primaryView : self.secondaryView,
toView: displayingPrimary ? self.secondaryView : self.primaryView,
duration: 1.0,
options: nil ) { (finish) -> Void in
if finish {
println("after:\(self.primaryView)")
self.displayingPrimary = !self.displayingPrimary;
}
}
this is print info in console
<UIView: 0x79fe3c80; frame = (0 0; 399 349); hidden = YES; autoresize = RM+BM; layer = <CALayer: 0x79fe3d10>>
after:<UIView: 0x79fe3c80; frame = (0 0; 399 349); hidden = YES; autoresize = RM+BM; layer = <CALayer: 0x79fe3d10>>
<UIView: 0x79fe3c80; frame = (0 0; 399 349); autoresize = RM+BM; layer = <CALayer: 0x79fe3d10>>
after:<UIView: 0x79fe3c80; frame = (-436 -328; 399 349); autoresize = RM+BM; layer = <CALayer: 0x79fe3d10>>
I have a ViewController and some label and textfield for user to input, and in some point I need to loop over all textfield to collect the user's input.
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.configureView()
for views in self.view.subviews {
if view is UITextField
{
println("inside")
}
println(views.description)
}
}
For this code, the "inside" never print out. But I do see some the information of views.description
<UILabel: 0x7fa4b1c7bd00; frame = (16 97; 76 21); text = 'FromDate'; opaque = NO; autoresize = RM+BM; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x7fa4b1c44580>>
<UILabel: 0x7fa4b1c9fd60; frame = (16 169; 82 21); text = 'ControlNO'; opaque = NO; autoresize = RM+BM; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x7fa4b1c77fb0>>
>
<UITextField: 0x7fa4b1c7a050; frame = (106 95; 197 30); text = ''; clipsToBounds = YES; opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x7fa4b1c6c800>>
<UITextField: 0x7fa4b1c9c060; frame = (106 126; 197 30); text = ''; clipsToBounds = YES; opaque = NO; autoresize = RM+BM; tag = 1; layer = <CALayer: 0x7fa4b1c9c2c0>>
<_UILayoutGuide: 0x7fa4b1d11d20; frame = (0 0; 0 0); hidden = YES; layer = <CALayer: 0x7fa4b1d11e00>>
<_UILayoutGuide: 0x7fa4b1d253f0; frame = (0 0; 0 0); hidden = YES; layer = <CALayer: 0x7fa4b1d12f60>>
but if I println(views.dynamicType) I could only see ExistentialMetatype.
What is wrong in my code?
The loop variable is called views, but you test view (which is
not the loop variable and therefore identical to self.view):
for views in self.view.subviews { // "views" here
if view is UITextField { // "view" here
println("inside")
}
}
If you rename the loop variable to view
for view in self.view.subviews {
if view is UITextField {
println("inside")
}
}
then everything works as expected.
You can use isKindOfClass:
var tex = UITextField()
if tex.isKindOfClass(UITextField){
println("yes")
}
#Christian's code will work. Here is another solution.
if let view = tex as? UITextField {
// view is a UITextField
}
I am working on one app. Which capture images continuously, there is one button to stop capturing. But the problem is that button targeted method is not being called. Even when I clicked on the screen anywhere it didn't detect touch or gesture. I have implemented gesture and touch delegate methods to check. Capturing image is not on main thread so main thread is free. So I am not able to find the reason why view not able to detect the touch. There are almost 6-7 button on that particular view, none of them trigger their method. While working with ios7 its running properly, It will detect touch and button targeted method trigger also.
I have thought that there should be any-view that will be overlap those button so i print the stake of subview , which is as below.Button which stop capturing is with text "START". I have just share stake after START button only as i think in stake the last item will be on top in view.
<UIButtonLabel: 0x15dfb0d0; frame = (5 14; 41 16); text = 'START';
opaque = NO; userInteractionEnabled = NO; layer = <_UILabelLayer:
0x15dfb190>>
<UIButton: 0x15e8c590; frame = (63 7; 36 32); opaque = NO; autoresize
= RM+BM; layer = <CALayer: 0x15e8c690>>
<UIButtonLabel: 0x15df0400; frame = (15 10; 6 12); text = '0'; opaque
= NO; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x15d98db0>>
<UIImageView: 0x15e97c00; frame = (-295 -272; 1557 1568);
clipsToBounds = YES; hidden = YES; autoresize = W+H;
autoresizesSubviews = NO; layer = <CALayer: 0x15ea2920>>
<_UILayoutGuide: 0x15e90ba0; frame = (0 0; 0 0); hidden = YES; layer =
<CALayer: 0x15ea2b10>>
<_UILayoutGuide: 0x15e86120; frame = (0 1024; 0 0); hidden = YES;
layer = <CALayer: 0x15e6fc40>>
<MPVolumeView: 0x15db7840; frame = (18 340; 284 23); alpha = 0; opaque
= NO; layer = <CALayer: 0x15dbd2e0>>
<UILabel: 0x15daee40; frame = (0 0; 0 0); text = 'No Volume
Available'; opaque = NO; autoresize = W+BM; userInteractionEnabled =
NO; layer = <_UILabelLayer: 0x15dd5be0>>
<MPButton: 0x15dd5e00; baseClass = UIButton; frame = (131.5 2.5; 21.5
18); alpha = 0; opaque = NO; autoresize = LM+BM; layer = <CALayer:
0x15dd6030>>
<UIImageView: 0x15de0c30; frame = (-39.25 -41; 100 100); alpha = 0;
opaque = NO; userInteractionEnabled = NO; tag = 1886548836; layer =
<CALayer: 0x15ea5330>>
<UIImageView: 0x15ea5790; frame = (0 0; 21.5 18); clipsToBounds = YES;
opaque = NO; userInteractionEnabled = NO; layer = <CALayer:
0x15ea5810>>
I am using auto-layout. Please can you help me to handle this problem. I am new with auto-layout. so anything that i can change in storyboard get this problem solved please let me know. Thanks in advance.
Thanks for all your answers. I got solution by moving irate code from +initialize method of AppDelegate to didFinishLaunchingWithOptions method. My iRate get initialized and configure but don't show popup. May be that's why i was not able to perform any touch on screen.
I'm getting some issues with a constraint relative from the bottom layout.
There are some views inside a UITabBarViewController. When I change to another view from the tab and return to first one, the viewcontroller not recognize the bottom layout as the tab bar, but from the bottom of the view.
I uploaded the problem here: https://sites.google.com/site/rveducationapps/layoutError.png?attredirects=0&d=1
I already tried put in ViewDidAppear and also ViewWillAppear:
[self.view layoutSubviews];
[self.view setNeedsUpdateConstraints];
I logged the subviews in the two cases, the right one and after I exit and return to the view:
subviews:(
"<UIView: 0x146b2260; frame = (210 0; 814 712); autoresize = RM+BM; layer = <CALayer: 0x146b22c0>>",
"<UIButton: 0x146a9eb0; frame = (727 672; 287 30); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x146aa070>>",
"<UITableView: 0x151d3400; frame = (0 0; 210 761); clipsToBounds = YES; autoresize = W+H; gestureRecognizers = <NSArray: 0x146b14b0>; layer = <CALayer: 0x146ade20>; contentOffset: {0, 0}>",
"<_UILayoutGuide: 0x146b23b0; frame = (0 0; 0 20); hidden = YES; layer = <CALayer: 0x146b24a0>>",
"<_UILayoutGuide: 0x146b28a0; frame = (0 712; 0 56); hidden = YES; layer = <CALayer: 0x146b2910>>"
)
subviews:(
"<UIView: 0x146b2260; frame = (210 0; 814 768); autoresize = RM+BM; layer = <CALayer: 0x146b22c0>>",
"<UIButton: 0x146a9eb0; frame = (727 728; 287 30); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x146aa070>>",
"<UITableView: 0x151d3400; frame = (0 0; 210 817); clipsToBounds = YES; autoresize = W+H; gestureRecognizers = <NSArray: 0x146b14b0>; layer = <CALayer: 0x146ade20>; contentOffset: {0, 0}>",
"<_UILayoutGuide: 0x146b23b0; frame = (0 0; 0 20); hidden = YES; layer = <CALayer: 0x146b24a0>>",
"<_UILayoutGuide: 0x146b28a0; frame = (0 768; 0 0); hidden = YES; layer = <CALayer: 0x146b2910>>"
)
I see there are some differences, specially in:"<_UILayoutGuide: 0x146b28a0; frame = (0 712; 0 56); hidden = YES; layer = <CALayer: 0x146b2910>>"
But I don't know how to fix it.
EDITED:
I think I fixed. I selected the UIViewController in the Storyboard and disabled the EXTEND EDGES->Under Bottom Bars option.
If you are transitioning from your UITabBarViewController to a new UIViewController, and then attempting to go back to your tabBarController from that UIViewController, then you could simply segue back to the UITabBarViewController(The segue will take you back to your rootViewController for your UITabBarViewController).
If you need to transition back to a specific tab, instantiate a custom segue and send it back to a different tab using a different specified VC, this can be set in your UITabBarViewController class or in your applications AppDelegate.m file.
I add objects in UIScrollView inside cycle FOR, but after the second interaction the index of subviews change.
When i create the ScrollView:
scroll.subviews :(
"<UIImageView: 0x147aeee0; frame = (1017 186; 7 5); alpha = 0; opaque = NO; autoresize = TM; userInteractionEnabled = NO; layer = <CALayer: 0x147aef50>>",
"<UIImageView: 0x147aefa0; frame = (1019 184; 5 7); alpha = 0; opaque = NO; autoresize = LM; userInteractionEnabled = NO; layer = <CALayer: 0x147af010>>"
)
After i have the cycle FOR with [scroll addSubview:btn];
First
scroll.subviews :(
"<UIImageView: 0x147aeee0; frame = (1017 186; 7 5); alpha = 0; opaque = NO; autoresize = TM; userInteractionEnabled = NO; layer = <CALayer: 0x147aef50>>",
"<UIImageView: 0x147aefa0; frame = (1019 184; 5 7); alpha = 0; opaque = NO; autoresize = LM; userInteractionEnabled = NO; layer = <CALayer: 0x147af010>>",
"<ContentButton: 0x13fdc610; baseClass = UIButton; frame = (15 10; 221 173); opaque = NO; tag = 1; layer = <CALayer: 0x1034cc00>>"
)
Second (change last object to index 0)
scroll.subviews :(
"<ContentButton: 0x13fdc610; baseClass = UIButton; frame = (15 10; 221 173); opaque = NO; tag = 1; layer = <CALayer: 0x1034cc00>>",
"<UIImageView: 0x147aefa0; frame = (1019 184; 5 7); alpha = 0; opaque = NO; autoresize = LM; userInteractionEnabled = NO; layer = <CALayer: 0x147af010>>",
"<UIImageView: 0x147aeee0; frame = (1017 186; 7 5); alpha = 0; opaque = NO; autoresize = TM; userInteractionEnabled = NO; layer = <CALayer: 0x147aef50>>",
"<ContentButton: 0x105ddf70; baseClass = UIButton; frame = (246 10; 221 173); opaque = NO; tag = 149; layer = <CALayer: 0x105523e0>>"
)
Third and so on, the object will add normally (in last index)
scroll.subviews :(
"<ContentButton: 0x13fdc610; baseClass = UIButton; frame = (15 10; 221 173); opaque = NO; tag = 1; layer = <CALayer: 0x1034cc00>>",
"<UIImageView: 0x147aefa0; frame = (1019 184; 5 7); alpha = 0; opaque = NO; autoresize = LM; userInteractionEnabled = NO; layer = <CALayer: 0x147af010>>",
"<UIImageView: 0x147aeee0; frame = (1017 186; 7 5); alpha = 0; opaque = NO; autoresize = TM; userInteractionEnabled = NO; layer = <CALayer: 0x147aef50>>",
"<ContentButton: 0x105ddf70; baseClass = UIButton; frame = (246 10; 221 173); opaque = NO; tag = 149; layer = <CALayer: 0x105523e0>>",
"<ContentButton: 0x13f1dc80; baseClass = UIButton; frame = (477 10; 221 173); opaque = NO; tag = 3; layer = <CALayer: 0x13f1dd20>>"
)
The problem is in the second interaction, so why the last object (ContentButton) was in the index 2 and change into index 0?
for (obj * objScroll in arrayChaObj)
{
// UIButton
ContentButton * btn = [[ContentButton alloc] initWithFrame:CGRectMake(btContentPosXChaObj,
10,
imgButtonScroll.size.width,
imgButtonScroll.size.height)];
btContentPosXChaObj += 10 + imgButtonScroll.size.width;
[scroll addSubview:btn];
NSLog(#"scroll.subviews :%#",scroll.subviews);
[scroll setContentSize:CGSizeMake(btContentPosXChaObj, imgButtonScroll.size.height+10)];
}
This is just a wild guess.
What happens when you call setContentSize: for the first time? Well, the two image views end up outside the content region. They won't be ever displayed.
I guess the scrollview then optimizes the order of subviews and puts the invisible ones to the end which can probably improve its clipping (redrawing) functionality.
Currently I don't have the time to check this and experiment but it's a reasonable explanation for me.