Android - TalkBack accessibility focus on swipe to delete button in Recycleview - android-recyclerview

I have drawn the Swipe to delete button(RectF) in Recycle view with the help on
val oBackground = RectF(itemView.right.toFloat() - buttonWidth, itemView.top.toFloat(), itemView.right.toFloat(), itemView.bottom.toFloat())
paint.color = ContextCompat.getColor(viewHolder.itemView.context, R.color.color_cc0013)
canvas.drawRect(optionsBackground, paint)
// Displays delete drawable within specified bounds
val deleteBtmp: Bitmap = getBitmapFromVectorDrawable(viewHolder.itemView.context, R.drawable.vector_delete)
val destination = RectF(
itemView.right.toFloat() - buttonWidth + paddingLeft,
itemView.top.toFloat() + paddingTop,
itemView.right.toFloat() - paddingRight,
itemView.bottom.toFloat() - paddingBottom
)
canvas.drawBitmap(deleteBtmp, null, destination, paint)
How I can set TalkBack accessibility focus on swipe to delete button(deleteBtmp) in Recycleview ?

Your delete button is what we call a "virtual view". You'll need to expose it with an AccessibilityNodeProvider.
ExploreByTouchHelper is a wrapper intended to simplify the process.
Much simpler, however, would be to adjust your UI to use a regular button, and take advantage of the built-in accessibility reporting.

Related

Clickable box makes its "non-clickable parent box" clickable as well?

Here is the code snippet:
Box(
Modifier
.size(48.dp, 48.dp)
.background(Color.Transparent)
.align(Alignment.CenterEnd)
)
{
Box(
Modifier
.size(height = 35.636363.dp, width = 41.818181.dp)
.align(Alignment.CenterEnd)
.clip(RoundedCornerShape(topStart = 20.dp, bottomStart = 20.dp))
.clickable(onClick = {showDialogFragment.value = true})
.background(Color.Red)
)
}
Whenever i click on parent box (the one which is transparent) it activates click event of its only child. Why so? Current behavior meets my needs, but i dont understand why it happens.
According to Material Guidelines, the minimum touch size is 48.dp.
Since 1.1.0-alpha03, when you add touch detection to a view with a size smaller than this value, tracking will work on the enlarged frame.
Added minimum touch target size to ViewConfiguration for use in semantics and pointer input to ensure accessibility.
Just out of curiosity, you can check the extended touch padding for the current view using pointerInput modifier, which lies under all touch processing in Compose:
.pointerInput(Unit) {
println("$extendedTouchPadding")
}

Haxe: Handling horizontal scroll events

I recently started using Haxe, so pardon me if my question has an obvious answer or if my description of the problem is a little sloppy, but I'm going to try my best to explain it.
I'm working on a laptop that has a multitouch-supported track pad, and a normal optical mouse with only a vertical scroll wheel (no horizontal clicking available on there). I'm looking for a way to handle horizontal scroll input / events. OpenFL's mouse events support vertical scrolling well enough. Both the mouse scrolling and the two-finger track pad scrolling work fine for the vertical axis. It looks like the same event is generated when either of those input methods are used, which is understandable. But I can't seem to find an event that would be generated when a horizontal scroll is performed. The track pad allows for horizontal scrolling, since web browsers respond to the command, but I can't find any way to make my program respond to this input. Lime's "onMouseWheel" function doesn't respond to the input either. Do you guys have any suggestions for capturing this kind of input for an app targeted for Windows?
Thanks in advance
UPDATE: What I'm looking for here is not a question of how to scroll the screen horizontally, but how to recognize the horizontal scroll event coming from hardware, for example two fingers on the track pad or a sideways click of the middle mouse wheel. Lime's onMouseWheel has two params, deltaX and deltaY, but no events are triggered that give back a non-zero deltaX value. Vertical scrolling fires an event that returns deltaX = 0 and deltaY = +/- 1, but horizontal scrolling doesn't even trigger an event.
This can be done in several ways. The first is to add an event handler to mouse wheel for the object instance that you want to attach the event handler to, so MouseEvent.MOUSE_WHEEL and use the delta variable to determine the scroll direction. What you may also need to do is handle a key down event which enables horizontal scrolling instead of vertical.
Some example code:
mySprite.addEventHandler(MouseEvent.MOUSE_WHEEL, onScroll);
mySprite.addEventHandler(KeyboardEvent.KEY_DOWN, onKeyDown);
mySprite.addEventHandler(KeyboardEvent.KEY_UP, onKeyUp);
...
private var horizontal:Bool;
private function onScroll(e:MouseEvent):Void
{
if (e.delta > 0 && horizontal)
mySprite.scrollRect.x++;
else if (e.delta < 0 && horizontal)
mySprite.scrollRect.x--;
}
private function onKeyDown(e:KeyboardEvent):Void
{
if (e.keyCode == 18)
horizontal = true;
}
private function onKeyUp(e:KeyboardEvent):Void
{
if (e.keyCode == 18)
horizontal = false;
}
You will need to define the scrollRect in your constructor somewhere to specify the scrolling bounds of the sprite.

Custom context menu XAML for WP8

I try to implement a custom ContextMenu in a LongListSelector.
I'm not using the ContextMenu from Microsoft.Phone.Controls.Toolkit, it's basically the same as in the Rowi App:
(source: hiddenpineapple.com)
Approach 1
My list item toggles a VisualState on hold and an overlay is shown with controls in it.
The problem
I can't find a way to go back to the default state when the user clicks outside of the list item (as in the default ContextMenu).
Approach 2
I've implemented a custom template for the toolkit ContextMenu which looks exactly the same. I had to move its margin top to -itemHeight, as by default it is below the item.
The problem
The problem with this solution is, that it automatically closes itself when opening and I couldn't figure out how to avoid this.
Another problem was that it didn't work well with TiltEffect.IsTiltEnabled from the Toolkit (visual problems).
I need your help
Any suggestions on how to get this working?
Answer
Thanks to Cheese, now I know how to properly close the menu when the user clicks outside.
His suggestion was to get the coordinates of a Tap event on the current page, and check if it's inside the menu. When not, close the menu.
So I added a Tap listener to the page when the menu opens, and removed it when the menu closes. From the page listener I got the event coordinates and could check if it's inside the control which holds the menu (same size and position). I received the position of the control with Point leftUpperPoint = control.TransformToVisual(page).Transform(new Point(0, 0)) and the rightLowerPoint by adding the ActualWidth and ActualHeight.
But then I realized:
Why should I even calculate if the tap is inside the menu? I always want to close the menu when the user taps anywhere on the screen. If it's outside, yes. If it's on a menu button, yes.
Another modification I made was to listen for MouseLeftButtonDown instead of Tap as it also triggers when the user swipes.
So I removed this code and came up with the following:
private void ToggleMenu(object sender, System.Windows.Input.GestureEventArgs e)
{
PhoneApplicationFrame frame = ((PhoneApplicationFrame)Application.Current.RootVisual);
VisualState state = this.States.CurrentState;
if (state == null || state.Name == "DefaultState")
{
frame.MouseLeftButtonDown += MouseDownDelegate;
this.State = "MenuState";
}
else
{
frame.MouseLeftButtonDown -= MouseDownDelegate;
this.State = "DefaultState";
}
}
private void MouseDownDelegate(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
ToggleMenu(sender, null);
}
This works perfectly!
Thanks to Cheese for the hint.
Something like this by #denniscode http://dotnet.dzone.com/articles/rowi-show-tap-menu
Approach 1 problem
The best solution would be:
Get the menus coordinates, when user makes a tap - you check are tap coordinates on menu or not, if not - dissmiss - simple.
Approach 2 problem
I guess you had some button in a corner and when you tapped on it - nothing happened? And when you dissmissed the Tilt all worked. It seems that tilt works faster than a click, so, tilt changes the button coordinates, and device thiks you have missed/or dragged off
You can use what #ScottIsAFool suggested and maybe create another Dependency Property on your TapMenu control of type UIElement named CloseWhenTappedElement and automatically listen for Tap events inside your control once set. For example
<Grid x:Name="TapArea"/>
<TapMenu CloseWhenTappedElement="{Binding ElementName=TapArea"}/>

WinJS AppBar button flash on Hide

My application has a WinJS AppBar control at the bottom of the screen. I use .showOnlyCommands(buttonsToShowArray) to show and hide buttons on ListView itemSelectionChanged event.
The problem I have right now is that when every I call .showOnlyCommands, the buttons to be hidden (or you may say "replaced") are going to flash on the top of the screen.
I tried to use the Microsoft sample app, this doesn't happen. I tried to use .showCommands + .hideCommands method, it is the same behavior. Note that this didn't happen before the Release Preview version of Win8.
I have no idea what is going on. Any idea?
EDIT:
I did further investigation, the problem happens on hideCommands. Say I have 3 buttons displayed on the appbar. I call hideCommands to hide all 3 buttons. The icon of the 3 buttons would disappear on the appbar, then pile up at the top-left corner of the screen and then disappear. (i.e. there would be a flash of 3 piled up buttons at the corner of the screen).
You may be invoking showOnlyCommands when the AppBar is in the process of 'showing'. I've found that when calling these methods in the beforeshow or aftershow handler that this happens. This quote from Animating your UI sheds light on why:
Use fade in and fade out animations to show or hide transient UI or controls. One example is in an app bar in which new controls can appear due to user interaction.
The sample app shows/hides the buttons before the appbar is shown. You may be calling show on the app bar before calling showOnlyCommands.
A temporary hack for this problem is:
Set the button be invisible before calling showOnlyCommands or HideCommands.
Here is the code that I use for now:
/*
* #param {WinJS.UI.AppBar} appbar winControl
* #param {Array} array of appbar buttons to be shown
*/
function showOnlyCommands(appbarControl, buttonsToShow) {
var toShow = {};
for (var i = 0; i < buttonsToShow.length; i++) {
toShow[buttonsToShow[i].id] = true;
}
for (var i = 0; i < visibleButtonsList.length; i++) {
var id = visibleButtonsList[i].id;
if (!toShow[id]) {
// set the display property of the buttons to be hidden to "none"
var button = document.getElementById(id);
if (button) {
button.style.display = 'none';
}
}
}
// update the visible buttons list
visibleButtonsList = buttonsToShow;
// Note that we don't need to set the "display" property back for the buttons,
// because WinJS.UI.AppBar.showOnlyCommands would set it back internally
appbarControl.showOnlyCommands(buttonsToShow);
}

How to toggle visibility of NSSplitView subView + hide Pane Splitter divider?

We have a parent Split view (NSSplitView), and two subviews, Content and SideBar (the sidebar is on the right).
What would be the optimal Cocoa-friendly way to toggle the SideBar view?
I would really love it, if the suggested solution includes animation
I really don't need any suggestions related to external plugins, etc (e.g. BWToolkit)
HINT : I've been trying to do that, but still I had issues hiding the divider of the NSSplitView as well. How could I do it, while hiding it at the same time?
Here's a pretty decent tutorial that shows how to do this: Unraveling the Mysteries of NSSplitView.
Hiding the divider is done in NSSplitView's delegate method splitView:shouldHideDividerAtIndex:.
You will have to animate the frame size change yourself if you don't like the way NSSplitView does it.
Easiest way to do it is as follows - and it's animated: [SWIFT 5]
splitViewItems[1].animator().isCollapsed = true // Show side pane
splitViewItems[1].animator().isCollapsed = false // hide side pane
I wrote a Swift version of the content in the link from #Nathan's answer that works for me. In the context of my example splitView is set elsewhere, probably as an instance property on an encompassing class:
func toggleSidebar () {
if splitView.isSubviewCollapsed(splitView.subviews[1] as NSView) {
openSidebar()
} else {
closeSidebar()
}
}
func closeSidebar () {
let mainView = splitView.subviews[0] as NSView
let sidepanel = splitView.subviews[1] as NSView
sidepanel.hidden = true
let viewFrame = splitView.frame
mainView.frame.size = NSMakeSize(viewFrame.size.width, viewFrame.size.height)
splitView.display()
}
func openSidebar () {
let sidepanel = splitView.subviews[1] as NSView
sidepanel.hidden = false
let viewFrame = splitView.frame
sidepanel.frame.size = NSMakeSize(viewFrame.size.width, 200)
splitView.display()
}
These functions will probably methods in a class, they are for me. If your splitView can be nil you obviously have to check for that. This also assumes you have two subviews and the one at index 1, here as sidePanel is the one you want to collapse.
In Xcode 9.0 with Storyboards open Application Scene select View->Menu->Show sidebar. CTRL-click Show Sidebar, in sent actions delete the provided one, click on x. From the circle CTRL drag to First Responder in application scene and select toggleSideBar to connect to. Open storyboard and select the first split view item and in attributes inspector change behaviour from default to sidebar. Run and try with view menu item show/hide. All done in interface builder no code. toggleSideBar handles the first split view item. https://github.com/Dis3buted/SplitViewController
I got some artifacts with the code above, likely because it was out of context. I am sure it works where it was meant to. Anyway, here is a very streamlined implementation:
// this is the declaration of a left vertical subview of
// 'splitViewController', which is the name of the split view's outlet
var leftView: NSView {
return self.splitViewController.subviews[0] as NSView
}
// here is the action of a button that toggles the left vertical subview
// the left subview is always restored to 100 pixels here
#IBAction func someButton(sender: AnyObject) {
if splitViewController.isSubviewCollapsed(leftView) {
splitViewController.setPosition(100, ofDividerAtIndex: 0)
leftView.hidden = false
} else {
splitViewController.setPosition(0, ofDividerAtIndex: 0)
leftView.hidden = true
}
}
To see a good example using animations, control-click to download this file.
If your NSSplitView control is part of a NSSplitViewController object, then you can simply use this:
splitViewController.toggleSidebar(nil)