-
Notifications
You must be signed in to change notification settings - Fork 24.4k
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
Does even bubbling exist, or how to enable cancelsTouchesInView ? #30
Comments
Can you describe your use case? Hard to give a good answer without knowing what you are trying to do |
I'm doing something a little unconventional, which you saw me tweet about: throwing a UI on top of a game. It's primitive right now but looks like this: Those are up/down buttons at the bottom. Problem is, you can touch the screen to move around the camera, but if you press and drag your finger on top of those buttons, it still moves the camera around. My views are set up like this: one controller that has a normal UIView, the GL view as the first subview and the RCTRootView as the second subview. |
We have a responder system to handle this, but we didn't have much time to explain how it works at the conference. There are a number of handles that we use to negotiate touch handling. These are working well on View, but not everything has full support for this yet. (I'm not sure what 3D view you're using here) A view can become the touch responder by implementing the correct negotiation methods. There are two methods to ask the view if it wants to become responder:
If the View returns true and attempts to become the responder, one of the following will happen:
If the view is responding, the following handlers are used:
There are a few more features and facets to this system, which can be found in the highly documented |
Thanks for the explanation, @ericvicenti! After I posted this I did see the diagram in ResponderEventPlugin.js. I believe, however, that is doesn't fix my use case. All of this is only happening within the views controlled by ReactKit, correct? I'm rendering everything from ReactKit into it's own subview, and rendering everything from OpenGLES into a different subview. So basically I can't control how I interact with anything outside of the ReactKit subview, right? By default, all touches are being handled by both of these views. The right way to do it, it seems, is to implement my own custom GL view on the native side and expose that as a custom component. Then I can render the GL view within my component hierarchy, and I can control the interactions. Where should I start to look at implementing my own native UIView subclass? |
cc @jordwalke |
Correct- responder negotiation happens in JS. The 3D view should be expressed in your React component hierarchy to use the responder system. (There currently isn't good responder negotiation between the top-level ReactKit component and external iOS components.) I'll defer to @jordwalke, @sahrens, @frantic, and @nicklockwood to help explain the state-of-the-art when it comes to bridging new components. |
I think I see how. I need to create a component with a I'll take it from here and file an issues I run into. |
@jlongster Yes, that should work, but I don't know why your other view is receiving touches that started on the buttons. Are your touch handlers for the camera on the outermost view that contains everything? If so, you could put your touch handlers (or gesture recognizers) on just the part of the screen that has the teapot. |
@jordwalke The 3d scene is actually rendered the full width/height of the phone, and the buttons are sitting on top of it. I do it this way because the UI will frequently change on top of the 3d scene; it's basically just a 2d overlay. I could shrink the 3d scene, but there will be many other cases where I want an input on top of the scene. |
I see. Then your approach of creating a custom 3d-scene component sounds good. (BTW, we're going to streamline making new bridged components, and we're also going to work on integrating the JS cross-platform responder system with each platform's gestures). Also, where are your touch handlers? I think there's a way to make this work simply by making the buttons not under the place where your touch handlers are setup in iOS (regardless of geometry/how much space they take up). |
Cool, I assumed the bridge was early work and that it'll be easier to make custom components in the future. The touch handlers are on the view controller controlling the GL view. But I just realized that is the root view of the window. I add the RCTRootView as a subview on top of my GL view, but you're right, my touch handlers are still on the controller of the whole thing. I probably could try just having multiple controllers and make sure the UI is sitting on top of everything. |
@jlongster that sounds like the right approach (make sure the UI is really sitting on top of everything). |
…crash on simulator, on device I got nothing but app freezed)! My app has an old version of JSONKit which is still using MRC. I think JSONKit is not needed if system version is available. Kicking out of JSONKit will make react native stronger. Crash stack: * thread facebook#11: tid = 0xbd672f, 0x000000010a10edeb imobii-waiqin`jk_encode_add_atom_to_buffer(encodeState=0x00007f9b820a1000, objectPtr=22 key/value pairs) + 16971 at JSONKit.m:2807, name = 'com.facebook.React.JavaScript', stop reason = EXC_BAD_ACCESS (code=EXC_I386_GPFLT) frame #0: 0x000000010a10edeb imobii-waiqin`jk_encode_add_atom_to_buffer(encodeState=0x00007f9b820a1000, objectPtr=22 key/value pairs) + 16971 at JSONKit.m:2807 frame facebook#1: 0x000000010a10ef67 imobii-waiqin`jk_encode_add_atom_to_buffer(encodeState=0x00007f9b820a1000, objectPtr=2 key/value pairs) + 17351 at JSONKit.m:2811 frame facebook#2: 0x000000010a10ef67 imobii-waiqin`jk_encode_add_atom_to_buffer(encodeState=0x00007f9b820a1000, objectPtr=25 key/value pairs) + 17351 at JSONKit.m:2811 frame facebook#3: 0x000000010a10e768 imobii-waiqin`jk_encode_add_atom_to_buffer(encodeState=0x00007f9b820a1000, objectPtr=@"3 elements") + 15304 at JSONKit.m:2778 * frame facebook#4: 0x000000010a10a26a imobii-waiqin`-[JKSerializer serializeObject:options:encodeOption:block:delegate:selector:error:](self=0x00007f9b831fbc80, _cmd="serializeObject:options:encodeOption:block:delegate:selector:error:", object=@"3 elements", optionFlags=0, encodeOption=10, block=0x0000000000000000, delegate=0x0000000000000000, selector=<no value available>, error=domain: class name = NSInvocation - code: 0) + 2250 at JSONKit.m:2876 frame facebook#5: 0x000000010a109992 imobii-waiqin`+[JKSerializer serializeObject:options:encodeOption:block:delegate:selector:error:](self=JKSerializer, _cmd="serializeObject:options:encodeOption:block:delegate:selector:error:", object=@"3 elements", optionFlags=0, encodeOption=10, block=0x0000000000000000, delegate=0x0000000000000000, selector=<no value available>, error=domain: class name = NSInvocation - code: 0) + 178 at JSONKit.m:2831 frame facebook#6: 0x000000010a10f700 imobii-waiqin`-[NSArray(self=@"3 elements", _cmd="JSONStringWithOptions:error:", serializeOptions=0, error=domain: class name = NSInvocation - code: 0) JSONStringWithOptions:error:] + 112 at JSONKit.m:2985 frame facebook#7: 0x000000010ac13c02 imobii-waiqin`_RCTJSONStringifyNoRetry(jsonObject=@"3 elements", error=domain: class name = NSInvocation - code: 0) + 338 at RCTUtils.m:49 frame facebook#8: 0x000000010ac13990 imobii-waiqin`RCTJSONStringify(jsonObject=@"3 elements", error=0x0000000000000000) + 128 at RCTUtils.m:77 frame facebook#9: 0x000000010ab5fdfa imobii-waiqin`__27-[RCTContextExecutor setUp]_block_invoke_2(.block_descriptor=<unavailable>, moduleName=@"UIManager") + 218 at RCTContextExecutor.m:363 frame facebook#10: 0x00000001134495cc CoreFoundation`__invoking___ + 140 frame facebook#11: 0x000000011344941e CoreFoundation`-[NSInvocation invoke] + 286 frame facebook#12: 0x000000010db13db3 JavaScriptCore`JSC::ObjCCallbackFunctionImpl::call(JSContext*, OpaqueJSValue*, unsigned long, OpaqueJSValue const* const*, OpaqueJSValue const**) + 451 frame facebook#13: 0x000000010db13926 JavaScriptCore`JSC::objCCallbackFunctionCallAsFunction(OpaqueJSContext const*, OpaqueJSValue*, OpaqueJSValue*, unsigned long, OpaqueJSValue const* const*, OpaqueJSValue const**) + 262 frame facebook#14: 0x000000010db14bad JavaScriptCore`long long JSC::APICallbackFunction::call<JSC::ObjCCallbackFunction>(JSC::ExecState*) + 573 frame facebook#15: 0x000000010dade340 JavaScriptCore`JSC::LLInt::setUpCall(JSC::ExecState*, JSC::Instruction*, JSC::CodeSpecializationKind, JSC::JSValue, JSC::LLIntCallLinkInfo*) + 528 frame facebook#16: 0x000000010dae535d JavaScriptCore`llint_entry + 22900 frame facebook#17: 0x000000010dadf7d9 JavaScriptCore`vmEntryToJavaScript + 326 frame facebook#18: 0x000000010d9b1959 JavaScriptCore`JSC::JITCode::execute(JSC::VM*, JSC::ProtoCallFrame*) + 169 frame facebook#19: 0x000000010d9985ad JavaScriptCore`JSC::Interpreter::executeCall(JSC::ExecState*, JSC::JSObject*, JSC::CallType, JSC::CallData const&, JSC::JSValue, JSC::ArgList const&) + 493 frame facebook#20: 0x000000010d76cb7e JavaScriptCore`JSC::call(JSC::ExecState*, JSC::JSValue, JSC::CallType, JSC::CallData const&, JSC::JSValue, JSC::ArgList const&) + 62 frame facebook#21: 0x000000010d929a55 JavaScriptCore`JSC::callGetter(JSC::ExecState*, JSC::JSValue, JSC::JSValue) + 149 frame facebook#22: 0x000000010dad49fb JavaScriptCore`llint_slow_path_get_by_id + 2203 frame facebook#23: 0x000000010dae22f0 JavaScriptCore`llint_entry + 10503 frame facebook#24: 0x000000010dae5368 JavaScriptCore`llint_entry + 22911 frame facebook#25: 0x000000010dae52fd JavaScriptCore`llint_entry + 22804 frame facebook#26: 0x000000010dae5368 JavaScriptCore`llint_entry + 22911 frame facebook#27: 0x000000010dae5368 JavaScriptCore`llint_entry + 22911 frame facebook#28: 0x000000010dae52fd JavaScriptCore`llint_entry + 22804 frame facebook#29: 0x000000010dae5368 JavaScriptCore`llint_entry + 22911 frame facebook#30: 0x000000010dae5368 JavaScriptCore`llint_entry + 22911 frame facebook#31: 0x000000010dae5368 JavaScriptCore`llint_entry + 22911 frame facebook#32: 0x000000010dae552a JavaScriptCore`llint_entry + 23361 frame facebook#33: 0x000000010dae5368 JavaScriptCore`llint_entry + 22911 frame facebook#34: 0x000000010dae5368 JavaScriptCore`llint_entry + 22911 frame facebook#35: 0x000000010dadf7d9 JavaScriptCore`vmEntryToJavaScript + 326 frame facebook#36: 0x000000010d9b1959 JavaScriptCore`JSC::JITCode::execute(JSC::VM*, JSC::ProtoCallFrame*) + 169 frame facebook#37: 0x000000010d998264 JavaScriptCore`JSC::Interpreter::execute(JSC::ProgramExecutable*, JSC::ExecState*, JSC::JSObject*) + 10404 frame facebook#38: 0x000000010d7a8786 JavaScriptCore`JSC::evaluate(JSC::ExecState*, JSC::SourceCode const&, JSC::JSValue, WTF::NakedPtr<JSC::Exception>&) + 470 frame facebook#39: 0x000000010d9f6fb8 JavaScriptCore`JSEvaluateScript + 424 frame facebook#40: 0x000000010ab6379e imobii-waiqin`__68-[RCTContextExecutor executeApplicationScript:sourceURL:onComplete:]_block_invoke.264(.block_descriptor=<unavailable>) + 414 at RCTContextExecutor.m:589 frame facebook#41: 0x000000010ab63262 imobii-waiqin`__68-[RCTContextExecutor executeApplicationScript:sourceURL:onComplete:]_block_invoke(.block_descriptor=<unavailable>) + 498 at RCTContextExecutor.m:589 frame facebook#42: 0x000000010ab63df8 imobii-waiqin`-[RCTContextExecutor executeBlockOnJavaScriptQueue:](self=0x00007f9b832f6040, _cmd="executeBlockOnJavaScriptQueue:", block=0x00007f9b80c92970) + 248 at RCTContextExecutor.m:627 frame facebook#43: 0x000000010eb1d7a7 Foundation`__NSThreadPerformPerform + 283 frame facebook#44: 0x0000000113486301 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17 frame facebook#45: 0x000000011347c22c CoreFoundation`__CFRunLoopDoSources0 + 556 frame facebook#46: 0x000000011347b6e3 CoreFoundation`__CFRunLoopRun + 867 frame facebook#47: 0x000000011347b0f8 CoreFoundation`CFRunLoopRunSpecific + 488 frame facebook#48: 0x000000010ab5e41b imobii-waiqin`+[RCTContextExecutor runRunLoopThread](self=RCTContextExecutor, _cmd="runRunLoopThread") + 363 at RCTContextExecutor.m:284 frame facebook#49: 0x000000010ebc012b Foundation`__NSThread__start__ + 1198 frame facebook#50: 0x00000001140869b1 libsystem_pthread.dylib`_pthread_body + 131 frame facebook#51: 0x000000011408692e libsystem_pthread.dylib`_pthread_start + 168 frame facebook#52: 0x0000000114084385 libsystem_pthread.dylib`thread_start + 13
I don't see a
stopPropagation
method on the Event instance we get in a touch handler. Is there a way to do the equivalent of settingcancelsTouchesInView = YES
on a view so that touch events do not go to parent views?We probably don't need something like
stopPropagation
because you can't really do that on iOS, but some static property to set on aView
.The text was updated successfully, but these errors were encountered: