Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes the issue where it was not possible to perform a touch through the TouchThroughView #10

Open
wants to merge 40 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
19fdffb
Removed @Override annotation for compatibility with RN 47+
MonsieurBon Dec 4, 2017
201e373
Switched SimpleViewManager to ViewGroupManager
MonsieurBon Dec 4, 2017
e7e6a06
Merge branch 'master' of https://github.com/rome2rio/react-native-tou…
Dec 22, 2017
aaeb029
Fix issue #8 where the touch goes not through TouchThroughView
Dec 22, 2017
fca9108
Pod spec added
Mar 9, 2018
a68efdb
Example for react-native-navigation
Apr 15, 2018
e639732
Fix wrong typing
Apr 15, 2018
3d77905
Merge pull request #2 from punchh/master
simonhoss Apr 16, 2018
c3aa810
Adds package.json "description" field.
traviswimer Nov 29, 2018
7d2edae
Removes unnecessary log output code.
traviswimer Nov 29, 2018
0a2634b
Merge pull request #4 from traviswimer/master
simonhoss Dec 2, 2018
2962380
gradle fix
Jan 12, 2019
beb6c5f
Merge branch 'master' of https://github.com/simonhoss/react-native-to…
Jan 12, 2019
79d9f52
chore: new version
Jan 12, 2019
34137bb
chore: fix package.json
Jan 12, 2019
4668b66
fix: setActivityListener NullPointerException
Jan 12, 2019
1dd1a33
Merge pull request #6 from simonhoss/null_check_setActivityListener
simonhoss Jan 12, 2019
e00120c
chore: new version
Jan 12, 2019
cee3d48
Get versions from project instead
bondehagen Mar 3, 2019
7655fe8
Merge pull request #9 from bondehagen/patch-1
simonhoss Mar 3, 2019
d7d76b2
1.0.2
Mar 3, 2019
ac9258f
fix: calculating of the ToughThroughView
Apr 13, 2019
0ae415a
1.1.0-beta.0
Apr 13, 2019
f689daf
new version
Apr 27, 2019
8935d98
Fix TouchThroughView detection on Android
adapptor-jez Aug 9, 2019
a815925
(minor) Clean up unnecessary ternary operator
adapptor-jez Aug 15, 2019
32c78c2
Merge pull request #12 from adapptor-jez/fix-touch-through-view-detec…
simonhoss Sep 4, 2019
7facceb
Merge branch 'master' of https://github.com/simonhoss/react-native-to…
Sep 4, 2019
ece3050
new version for #12
Sep 4, 2019
0d65f52
Add support for multiple listeners
tankers746 Mar 10, 2020
683a3e0
Merge pull request #15 from fleeteng/master
simonhoss Mar 12, 2020
265ab2a
new beta version
Mar 13, 2020
b681d75
Update build.gradle
Brianop Mar 20, 2020
c0964a0
Fix podspec to reference correct source url
1e1f Mar 25, 2020
b55db09
Check for null getCurrentActivity
tankers746 Apr 18, 2020
8d643b5
Fix null handler
tankers746 Apr 18, 2020
b91c3f3
Incorrect null check
tankers746 Apr 18, 2020
c4c0e38
Merge pull request #17 from Brianop/patch-1
simonhoss Apr 30, 2020
bd4cef7
Merge pull request #18 from 1e1f/patch-1
simonhoss Apr 30, 2020
6e384e0
Merge pull request #19 from fleeteng/master
simonhoss Apr 30, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,5 @@ project.xcworkspace
*.iml
.gradle
local.properties
android/build
android/build
**/.DS_Store
39 changes: 37 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,43 @@ eg.

Have a look at the demo in the example directory if you need more help.

## Issues
Currently we are working through an issue at #8 with Android devices on that latest version of React Native not properly passing through touch events.
## Android Installation
For Android you have to do the normal react-native link. Also you have to change MainActivity inside you project. See example below

```java
package com.reactnativetouchthroughviewexample;

import com.facebook.react.ReactActivity;
import android.view.MotionEvent;
import com.rome2rio.android.reactnativetouchthroughview.TouchThroughTouchHandlerInterface;
import com.rome2rio.android.reactnativetouchthroughview.TouchThroughTouchHandler;

public class MainActivity extends ReactActivity implements TouchThroughTouchHandlerInterface {

private TouchThroughTouchHandler touchThroughTouchHandler = new TouchThroughTouchHandler();

/**
* Returns the name of the main component registered from JavaScript.
* This is used to schedule rendering of the component.
*/
@Override
protected String getMainComponentName() {
return "reactnativetouchthroughviewexample";
}

public TouchThroughTouchHandler getTouchThroughTouchHandler() {
return touchThroughTouchHandler;
}

@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
touchThroughTouchHandler.handleTouchEvent(ev);

return super.dispatchTouchEvent(ev);
}
}

```

## Credits
Brought to you by the team at [Rome2rio](https://www.rome2rio.com). Find out how to join our team at <https://www.rome2rio.com/careers/>
16 changes: 16 additions & 0 deletions RNTouchThroughView.podspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
require 'json'
package = JSON.parse(File.read('package.json'))

Pod::Spec.new do |s|
s.name = "RNTouchThroughView"
s.version = package["version"]
s.summary = package["description"]
s.requires_arc = true
s.license = package["license"]
s.homepage = 'n/a'
s.authors = { package["author"] => package["repository"]["url"] }
s.source = { :git => package["repository"]["url"] }
s.source_files = ['ios/*.{h,m}']
s.platform = :ios, "8.0"
s.dependency 'React'
end
11 changes: 8 additions & 3 deletions android/build.gradle
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
apply plugin: 'com.android.library'

def DEFAULT_COMPILE_SDK_VERSION = 23
def DEFAULT_BUILD_TOOLS_VERSION = "23.0.3"
def DEFAULT_TARGET_SDK_VERSION = 23

buildscript {
repositories {
google()
jcenter()
}
dependencies {
Expand All @@ -16,6 +20,7 @@ buildscript {

allprojects {
repositories {
google()
mavenLocal()
jcenter()
maven {
Expand All @@ -29,12 +34,12 @@ allprojects {


android {
compileSdkVersion 23
buildToolsVersion "23.0.3"
compileSdkVersion project.hasProperty('compileSdkVersion') ? project.compileSdkVersion : DEFAULT_COMPILE_SDK_VERSION
buildToolsVersion project.hasProperty('buildToolsVersion') ? project.buildToolsVersion : DEFAULT_BUILD_TOOLS_VERSION

defaultConfig {
minSdkVersion 16
targetSdkVersion 23
targetSdkVersion project.hasProperty('targetSdkVersion') ? project.targetSdkVersion : DEFAULT_TARGET_SDK_VERSION
}

lintOptions {
Expand Down
2 changes: 1 addition & 1 deletion android/gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.0-bin.zip
distributionUrl=https://services.gradle.org/distributions/gradle-2.10-all.zip
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.rome2rio.android.reactnativetouchthroughview;

import android.view.MotionEvent;

import java.util.ArrayList;
import java.util.List;

public class TouchThroughTouchHandler {

private List<TouchThroughTouchHandlerListener> listeners = new ArrayList();

public void addListener(TouchThroughTouchHandlerListener listener) {
listeners.add(listener);
}

public void removeListener(TouchThroughTouchHandlerListener listener) {
listeners.remove(listener);
}

public void handleTouchEvent(MotionEvent ev) {
for (TouchThroughTouchHandlerListener listener : listeners) {
listener.handleTouch(ev);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.rome2rio.android.reactnativetouchthroughview;

import android.view.MotionEvent;

public interface TouchThroughTouchHandlerInterface {
public TouchThroughTouchHandler getTouchThroughTouchHandler();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.rome2rio.android.reactnativetouchthroughview;

import android.view.MotionEvent;

public abstract class TouchThroughTouchHandlerListener {
abstract void handleTouch(MotionEvent ev);
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package com.rome2rio.android.reactnativetouchthroughview;

import com.facebook.react.uimanager.SimpleViewManager;
import com.facebook.react.uimanager.ThemedReactContext;
import com.facebook.react.uimanager.ViewGroupManager;

public class TouchThroughViewManager
extends SimpleViewManager<TouchThroughView> {
extends ViewGroupManager<TouchThroughView> {

public static final String REACT_CLASS = "R2RTouchThroughView";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ public List<NativeModule> createNativeModules(ReactApplicationContext reactConte
return Collections.emptyList();
}

@Override
public List<Class<? extends JavaScriptModule>> createJSModules() {
return Collections.emptyList();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,49 +1,94 @@
package com.rome2rio.android.reactnativetouchthroughview;

import com.facebook.react.views.view.ReactViewGroup;
import com.facebook.react.touch.ReactHitSlopView;
import com.facebook.react.bridge.ReactContext;

import android.app.Activity;
import android.content.Context;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.graphics.Rect;
import android.view.ViewGroup;

public class TouchThroughWrapper extends ReactViewGroup {
public TouchThroughWrapper(Context context) {
public class TouchThroughWrapper extends ReactViewGroup implements ReactHitSlopView {
private boolean lastTouchWasNotValid = false;
private final ViewGroup viewGroup = this;
private TouchThroughTouchHandler handler;

public TouchThroughWrapper(ReactContext context) {
super(context);
if (context == null) {
return;
}
Activity activity = context.getCurrentActivity();
if (activity == null) {
return;
}
if (activity instanceof TouchThroughTouchHandlerInterface) {
TouchThroughTouchHandlerInterface handlerInterface = (TouchThroughTouchHandlerInterface) activity;
handler = handlerInterface.getTouchThroughTouchHandler();
} else {
throw new RuntimeException("TouchThroughTouchHandlerInterface was not set on app activity");
}
}

@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
// Recursively find out if an absolute x/y position is hitting a child view and stop event
// propagation if a hit is found.
return this.isTouchingTouchThroughView(this, Math.round(event.getX()), Math.round(event.getY()));
return lastTouchWasNotValid;
}

private TouchThroughTouchHandlerListener listener = new TouchThroughTouchHandlerListener() {
@Override
void handleTouch(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
lastTouchWasNotValid = isTouchingTouchThroughView(viewGroup, (int) ev.getX(), (int) ev.getY());
}
}
};
public void addActivityListener() {
if(handler != null) {
handler.addListener(listener);
}
}

public void removeActivityListener() {
if(handler != null) {
handler.removeListener(listener);
}
}

// Recursively find out if an absolute x/y position is hitting a child view and stop event
// propagation if a hit is found.
private boolean isTouchingTouchThroughView(ViewGroup viewgroup, int x, int y) {
boolean isTouchingTouchThroughView = false;

for(int i = 0; i < viewgroup.getChildCount(); i++) {
for (int i = 0; i < viewgroup.getChildCount(); i++) {
View child = viewgroup.getChildAt(i);

boolean isViewGroup = child instanceof ViewGroup;
boolean isTouchThroughView = child instanceof TouchThroughView;

if (isTouchThroughView) {
Rect bounds = new Rect();
isTouchingTouchThroughView = child.getGlobalVisibleRect(bounds) && bounds.contains(x, y);
/*
int[] location = new int[2];
int[] thisLocation = new int[2];

child.getLocationOnScreen(location);

//child.getLocationOnScreen(location);
this.getLocationOnScreen(thisLocation);

int childX = location[0] - thisLocation[0];
int childY = location[1] - thisLocation[1];

Rect bounds = new Rect(childX, childY, childX + child.getWidth(), childY + child.getHeight());
//Rect bounds = new Rect(childX, childY, childX + child.getWidth(), childY + child.getHeight());

isTouchingTouchThroughView = bounds.contains(x, y);
}
else if (isViewGroup) {
*/
} else if (isViewGroup) {
isTouchingTouchThroughView = this.isTouchingTouchThroughView((ViewGroup) child, x, y);
}

Expand All @@ -60,4 +105,12 @@ public boolean onTouchEvent(MotionEvent event) {
// Pass through touch events to layer behind.
return false;
}
}

//If the touch was not on the list make the slop rect small so react-native dont use this view as responder
public Rect getHitSlopRect() {
if (lastTouchWasNotValid) {
return new Rect(-1000, -1000, -1000, -1000);
}
return new Rect(0, 0, 0, 0);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,16 @@ public class TouchThroughWrapperManager
public String getName() {
return REACT_CLASS;
}

@Override
public TouchThroughWrapper createViewInstance(ThemedReactContext context) {
return new TouchThroughWrapper(context);
TouchThroughWrapper view = new TouchThroughWrapper(context);
view.addActivityListener();
return view;
}

@Override
public void onDropViewInstance(TouchThroughWrapper view) {
view.removeActivityListener();
}
}
28 changes: 28 additions & 0 deletions example-react-native-navigation/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Example for react-native-navigation

This example is copied from https://github.com/wix/react-native-navigation/tree/master/example

It shows how to implement react-native-navigation for android

## Javascript

An example for the javascript part is under the "Push" section and in the file: src/screens/types/Push.js

## Android

### Implementation Details

Use TouchThroughActivity from `android/app/src/main/java/com/example/TouchThroughActivity.java` as implementation for the `TouchThroughTouchHandlerInterface` interface

Add `<activity android:name=".TouchThroughActivity" />` to `AndroidManifest.xml`

Override `startActivity` in NavigationApplication

```java
@Override
public void startActivity(Intent intent) {
intent.setClass(NavigationApplication.instance, TouchThroughActivity.class);

super.startActivity(intent);
}
```
17 changes: 17 additions & 0 deletions example-react-native-navigation/android/.project
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>example</name>
<comment>Project example created by Buildship.</comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.buildship.core.gradleprojectbuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.buildship.core.gradleprojectnature</nature>
</natures>
</projectDescription>
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#Thu Apr 05 19:51:51 CEST 2018
connection.project.dir=
6 changes: 6 additions & 0 deletions example-react-native-navigation/android/app/.classpath
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8/"/>
<classpathentry kind="con" path="org.eclipse.buildship.core.gradleclasspathcontainer"/>
<classpathentry kind="output" path="bin"/>
</classpath>
23 changes: 23 additions & 0 deletions example-react-native-navigation/android/app/.project
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>app</name>
<comment>Project app created by Buildship.</comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.buildship.core.gradleprojectbuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.buildship.core.gradleprojectnature</nature>
</natures>
</projectDescription>
Loading