Android Espresso how to verify text is not present in recycler view? - android-testing

I have recycler view with children textviews. I would like to verify that a text is not present in the recycler view without the need of scrolling it.
Current solution works but is too hacky i think.
#Test(expected = PerformException.class)
public void verifyUserIsNotPresentInParticipantsList() {
onView(withId(R.id.fab)).perform(click());
onView(withId(R.id.recyclerView)).perform(scrollTo(hasDescendant(withText("My Text"))));
}

Related

Direct interaction (when VoiceOver is active) inside "allowsDirectInteraction" marked View does not work

Edit: Just noticed, that sometimes, it works, and sometimes not. And I do not know why.
I am making an App made mostly for blind, VoiceOver will probably be active. In one view I need to make my interactions and gestures myself. In there I am trying to make a zone that is directly interactable, so that the functionallity behind it works like there is no Voiceover active, even when it is. But when I do this, instead of printing text on double tap, VoiceOver always tells: "Zone direct interaction", or something similar (The testdevice is not set to english).
Does anyone has an idea what the problem could be?
This is my View:
struct MyView: View {
var body: some View {
TestView()
.accessibilityAddTraits(.allowsDirectInteraction)
}
}
And that is the TestView:
struct TestView: View {
var body: some View {
Rectangle()
.onTapGesture(count: 2) { print("A View was tapped") }
.onAppear { print("A View was created") }
}
}
When having a view that uses up all the space it cannot be made directly interactable as default as it seems. The user needs to do this himself using the rotor or the settings:
Settings App/Accessibility/VoiceOver/Rotor Actions/Direct Touch Apps/
When the App is checked in that setting the view marked with the trait .allowDirectInteraction does work as if VoiceOver is not active, though this should only be used for elements that are accessible on their own, and not as easy way to avoid making the app accessible for those parts!

swipe between views using scrollview - swift

in viewDidLoad :
viewPager.dataSource = self
--
extension DetailsViewController:ViewPagerDataSource{
func numberOfItems(_ viewPager:ViewPager) -> Int {
return dict!.count
}
func viewAtIndex(_ viewPager:ViewPager, index:Int, view:UIView?) -> UIView {
func viewAtIndex(_ viewPager:ViewPager, index:Int, view:UIView?) -> UIView {
return view
the result is slow , it does not show the animation of transition maybe cuz I return the scrollview view not normal view , and when I swipe to left it shows nothing (swipe backwards) , is there anything better to implement ?
thanks for help.
Your question isn't very clear, and then you post a BUNCH of code, including code that's irrelevant to your question. You should only post the parts that directly relate to your question.
It looks like what you want is a UIPageViewController. That manages an array of view controllers, each of which holds the contents of one page. You can either user it with a page curl animation like iBooks, or a scrolling mode. You want the scrolling mode.
If you search in the Xcode help (or online, it looks like the link to download the app isn't in Xcode 8) on "PhotoScroller" You'll find a demo app that illustrates how it works.
That app is written in Objective-C, but it will at least show you the UI it offers.
In order to use a UIPageViewController you'll have to restructure your detail view controller to manage an array of child view controllers instead of only using a single view controller.
If you want side scrolling AND up and down scrolling among a grid of tiles then you want a collection view instead, but that's more work to set up.

Escaping from Scrollable areas in tvOS

I understand the concept that the focus engine will decide what can be selected. It also seems that it moves linearly vertically or horizontally and tries to find the next closest neighbor whose view intersects that vertical or horizontal line.
The problem I haven't solved just yet is how to set things up so that panning to switch between focusable subviews does not get prevented if one of them has a scrollable area (like a map).
I have two collection views that take up the width of the screen and sit one on top of the other. I can pan to switch between these just fine. Here is the code that overrides their shared custom UICollectionView class
override public func canBecomeFocused() -> Bool {
return true
}
public override func shouldUpdateFocusInContext(context: UIFocusUpdateContext) -> Bool {
return true
}
public override func didUpdateFocusInContext(context: UIFocusUpdateContext, withAnimationCoordinator coordinator: UIFocusAnimationCoordinator) {
super.didUpdateFocusInContext(context, withAnimationCoordinator: coordinator)
}
In a separate view controller, I have a map view and a collection view above it. Both take up the width of the screen. I can pan to switch from the collection view down to the map view, but no matter how slow or fast I try to pan/swipe up, I cannot get the map view to lose its focus.
I did try adding some gesture recognizers and setting the delegate methods to try and make my GR win over the map view's scrolling GRs, but to no avail.
Any one else have similar experience? How do I get back out of the map view without having to add another dialogue or something to switch context back to the collection view?
Thank you in advance.
I'm sure there are a number of ways to solve the problem (like the one suggested in the comment by Eugene for example). In general, you'll probably need to determine when you want the focus to leave the map and trigger a focus update with setNeedsFocusUpdate(), updateFocusIfNeeded(). You would then override preferredFocusView (part of UIFocusEnvironment which is adopted by UIViewController and UIView among other things), to set the focus to whatever you want.
The real trick is to determine when it's appropriate to do this. A map is particularly hard because it's possible that it may scroll for a very long time prior to hitting a boundary (if it ever does). As such, you may need to utilize a button press as suggested by Eugene or perhaps by implementing some of the MKMapViewDelegate methods like mapView(_:regionWillChangeAnimated:) to determine when the map has moved a large distance. The "correct" answer would be determined by your desired behavior, of course.

How can I get an accessibility swipe to navigate a collection of subviews correctly?

A single swipe gesture is intended by Apple to move the VoiceOver cursor through screen items in order but mine don't because the user can move them around!
My main view has a set of buttons and labels, however it also has two collections of custom subviews, let's call the instances SVA1 to SVA9 & SVB1 to SVB9 in 'ascending order' from left to right. That is, SVA is one custom UIView class and SVB is the 2nd. When I drag, say, SVA3 to the current position of SVA6 then I end up with an order of SVA1, SVA2, SVA4, SVA5, SVA3, SVA6, SVA7, SVA8 & SVA9. The collections are 'linked' so that that same order would now also be mirrored in the SVB subview collection via my code.
My problem is that swiping to the right, expecting VoiceOver to read out my items as I see them on screen results in a different order. It gets quite a lot of them right but then will suddenly move the VoiceOver cursor from the first collection to the 2nd or change its direction. After a move my code is aware of the new order of all the subviews but I'd like to be able to get that information to VoiceOver.
Each custom subview is an accessibilityElement. Is there a way that I can tell VoiceOver to read back my items in the order I'd expect? I've come across the -accessibilityElementAtIndex: method but don't see whether or how that fits with my situation.
Thank you.
If you want to change the order then accessibilityElementAtIndex: and the rest of the UIAccessibilityContainer protocol is what you are looking for.
Assuming that you have an array called accessibleElements that store the elements in the order you want them to appear.
- (NSInteger)accessibilityElementCount {
return self.accessibleElements.count;
}
- (id)accessibilityElementAtIndex:(NSInteger)index {
return self.accessibleElements[index];
}
- (NSInteger)indexOfAccessibilityElement:(id)element {
return [self.accessibleElements indexOfObject:element];
}
The container can't be a accessibility element itself so you should also override isAccessibilityElement
- (BOOL)isAccessibilityElement {
return NO;
}

How to increment a selected table row on iPhone

If someone was able to help me with the following, that would be great!
So here is what I'm trying to do. My app is basically a rss reader. The topics of the rss entries are displayed in a table view. Tapping on an entry opens a web view which displays the whole story. To this web view I have added a toolbar with up and down arrows so the user would be able to jump to the next/previous story without leaving the web view and having to tap another entry in the table. My problem is that I have no idea how to archieve this. Maybe this is related to the structure of my app. My guess is that I have to somehow increment the selected row on tapping the button.
As I said, maybe the code is a bit complicated, so I've posted the whole project here: http://www.schimanke.com/flo.zip It would be great if someone could have a look and tell me what to do.
What you need is to know which row is currently selected on your model. Since you have a reference to the model from your webview, that's easy:
int row = [mainModel.blogEntries indexOfObject:mainModel.selectedBlogEntry];
So all you need after that is to show the next (or previous) entry. Based on your code, it goes like this:
- (void) showNextPrevEntry:(int)increment usingTheOldController:(BlogEntryController *)controller {
int row = [mainModel.blogEntries indexOfObject:mainModel.selectedBlogEntry];
if (row+increment<[mainModel.blogEntries count] && row+increment>=0) {
mainModel.selectedBlogEntry = [ mainModel.blogEntries objectAtIndex:row+increment];
controller.mainModel = mainModel;
[controller viewDidLoad];
}
}
I don't think it's healthy to call viewDidLoad. Maybe you need another method just for updating the current loaded view and call that from your viewDidLoad. Also I'm not sure why you are using notifications for handling the button presses from the toolbar, but it works. :)

Resources