Keyboard accessibility improvements (#24359)

Summary:
In order to meet our accessibility requirements we need to have full support for keyboard navigation. The Touchable components works with press/tap with a finger, but doesn't respond to 'enter' when using a keyboard. Navigation works fine. This PR adds an onClick listener to touchable views that have the onPress prop defined.

[Android] [Added] - Add View.OnClickListener to Touchable components when onPress is defined
Pull Request resolved: https://github.com/facebook/react-native/pull/24359

Differential Revision: D14971230

Pulled By: cpojer

fbshipit-source-id: ca5559ca1308ee6c338532a00dcea4d00fa57f42
This commit is contained in:
Sam Mathias Weggersen
2019-04-17 09:55:24 -07:00
committed by Facebook Github Bot
parent a1250da646
commit 01bcde3ed8
11 changed files with 97 additions and 2 deletions
@@ -6,10 +6,9 @@
package com.facebook.react.uimanager;
import android.graphics.Color;
import android.os.Build;
import androidx.core.view.ViewCompat;
import android.view.View;
import android.view.ViewParent;
import androidx.core.view.ViewCompat;
import com.facebook.react.R;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.uimanager.AccessibilityDelegateUtil.AccessibilityRole;
@@ -83,6 +83,7 @@ import java.util.Map;
.put("topLoadingStart", MapBuilder.of(rn, "onLoadingStart"))
.put("topSelectionChange", MapBuilder.of(rn, "onSelectionChange"))
.put("topMessage", MapBuilder.of(rn, "onMessage"))
.put("topClick", MapBuilder.of(rn, "onClick"))
// Scroll events are added as per task T22348735.
// Subject for further improvement.
.put("topScrollBeginDrag", MapBuilder.of(rn, "onScrollBeginDrag"))
@@ -12,6 +12,7 @@ import android.graphics.Rect;
import android.os.Build;
import android.view.View;
import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.common.MapBuilder;
@@ -21,10 +22,12 @@ import com.facebook.react.uimanager.PixelUtil;
import com.facebook.react.uimanager.PointerEvents;
import com.facebook.react.uimanager.Spacing;
import com.facebook.react.uimanager.ThemedReactContext;
import com.facebook.react.uimanager.UIManagerModule;
import com.facebook.react.uimanager.ViewGroupManager;
import com.facebook.react.uimanager.ViewProps;
import com.facebook.react.uimanager.annotations.ReactProp;
import com.facebook.react.uimanager.annotations.ReactPropGroup;
import com.facebook.react.uimanager.events.EventDispatcher;
import com.facebook.yoga.YogaConstants;
import java.util.Locale;
import java.util.Map;
@@ -223,6 +226,28 @@ public class ReactViewManager extends ViewGroupManager<ReactViewGroup> {
// handled in NativeViewHierarchyOptimizer
}
@ReactProp(name = "clickable")
public void setClickable(final ReactViewGroup view, boolean clickable) {
if (clickable) {
view.setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View v) {
final EventDispatcher mEventDispatcher = ((ReactContext)view.getContext()).getNativeModule(UIManagerModule.class)
.getEventDispatcher();
mEventDispatcher.dispatchEvent(new ViewGroupClickEvent(view.getId()));
}});
// Clickable elements are focusable. On API 26, this is taken care by setClickable.
// Explicitly calling setFocusable here for backward compatibility.
view.setFocusable(true /*isFocusable*/);
}
else {
view.setOnClickListener(null);
view.setClickable(false);
}
}
@ReactProp(name = ViewProps.OVERFLOW)
public void setOverflow(ReactViewGroup view, String overflow) {
view.setOverflow(overflow);
@@ -0,0 +1,32 @@
package com.facebook.react.views.view;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.uimanager.events.Event;
import com.facebook.react.uimanager.events.RCTEventEmitter;
/**
* Represents a Click on the ReactViewGroup
*/
public class ViewGroupClickEvent extends Event<ViewGroupClickEvent> {
private static final String EVENT_NAME = "topClick";
public ViewGroupClickEvent(int viewId) {
super(viewId);
}
@Override
public String getEventName() {
return EVENT_NAME;
}
@Override
public boolean canCoalesce() {
return false;
}
@Override
public void dispatch(RCTEventEmitter rctEventEmitter) {
rctEventEmitter.receiveEvent(getViewTag(), getEventName(), Arguments.createMap());
}
}