meliorence / react-native-snap-carousel

Swiper/carousel component for React Native featuring previews, multiple layouts, parallax images, performant handling of huge numbers of items, and more. Compatible with Android & iOS.
BSD 3-Clause "New" or "Revised" License
10.37k stars 2.29k forks source link

TV Support (keyboard arrow keys) #833

Closed CyberCyclone closed 3 years ago

CyberCyclone commented 3 years ago

Is this a bug report, a feature request, or a question?

Bug report / feature request

Have you followed the required steps before opening a bug report?

(Check the step you've followed - put an x character between the square brackets ([]).)

Have you made sure that it wasn't a React Native bug?

Can't see it being a react native bug.

Is the bug specific to iOS or Android? Or can it be reproduced on both platforms?

Android, I haven't tested it on iOS (tvOS) yet.

Is the bug reproductible in a production environment (not a debug one)?

I haven't tested it in production.

Environment

Environment: React:16.13.1 React native: 0.63.4 react-native-snap-carousel: 3.9.1

Target Platform: Android - Android TV 10 and Expo Snack

Expected Behavior

I'm trying to use this plugin for Android TV which relies on the keyboard keys (left, right, up, down). When using the keys, it should go left and right and snap to the next item. On Android TV, hitting left or right initially moves the item about 1/10th of the way. Hitting it again snaps to the next item, but the internal index is now out of alignment. Trying to replicate this in an Expo Snack "scrolls" the items but it doesn't snap them to the intended position.

It would be good to offer official support for keyboard actions so it snaps to an item on every left or right keystroke (which maps to a Android / tvOS remove).

Actual Behavior

Intended position:

image

Actual position (not snapped to middle):

image

Reproducible Demo

https://snack.expo.io/@11news/carousel-simple-example

Steps to Reproduce

(Write your steps so that anyone can reproduce the issue in the Snack demo you provided.)

  1. For Snack, clink inside the emulator to give it focus
  2. Hit the right key on the keyboard and see the items move
Chi-BaoHDwebsoft commented 3 years ago

Same issue

jeffreyabarrios commented 3 years ago

I'm facing the same issue, when navigating with arrow keys or the tv remote, there's a step in between the transition, and the page indicator doesn't update. Any fix?

CyberCyclone commented 3 years ago

I basically solved it by turning off the scroll (scrollEnabled = false) and using snapTo that were tied to events. You'll need the below:

import { TVEventHandler } from 'react-native';
import _ from 'underscore';
_tvEventHandler;

    _enableTVEventHandler(context) {
        this._tvEventHandler = new TVEventHandler();
        this._tvEventHandler.enable(this, _.throttle(function (cmp, evt) {
                if (evt && evt.eventType === 'right') {
                        context.carousel.current.snapToItem(context.carousel.current._activeItem + 1, true);
                } else if (evt && evt.eventType === 'up') {

                } else if (evt && evt.eventType === 'left') {
                        context.carousel.current.snapToPrev(true);
                } else if (evt && evt.eventType === 'down') {

                } else if (evt && evt.eventType === 'select') {
                    // Do something on item select.
                }
        }, 500, {trailing: false})); // Important!!!! Use 'underscore's throttle (or equivalent) as the event handler spams even on single presses
    }

       async componentDidMount() {
        this._enableTVEventHandler(this);
    }
<Carousel
                    ref={this.carousel}
                    data={posts}
                    renderItem={(item) => this.renderItem(item, this.props)}
                    keyExtractor={(item, index) => item.id.toString()} 
                    sliderWidth={sliderWidth}
                    itemWidth={335}
                    enableSnap={true}
                    useScrollView={false}
                    initialNumToRender={10}
                    maxToRenderPerBatch={10}
                    windowSize={11}
                    scrollEnabled={false}
                />
CyberCyclone commented 3 years ago

Also use the beta version 4.0.0.x-beta of react-native-snap-carousel. It's a lot less buggy and I had issues with using snapTo not focusing / animating when using version 3.9.1

jeffreyabarrios commented 3 years ago

Also use the beta version 4.0.0.x-beta of react-native-snap-carousel. It's a lot less buggy and I had issues with using snapTo not focusing / animating when using version 3.9.1

Is it stable enough to be used in production? Would you recommend?

CyberCyclone commented 3 years ago

Also use the beta version 4.0.0.x-beta of react-native-snap-carousel. It's a lot less buggy and I had issues with using snapTo not focusing / animating when using version 3.9.1

Is it stable enough to be used in production? Would you recommend?

Seems solid enough based on the tests I've done (only Android 10 / Google TV). Not sure about tvOS (Apple). I did read a comment from the plugin author saying they were using it in production. It's up to version 6 of beta.

jeffreyabarrios commented 3 years ago

Also use the beta version 4.0.0.x-beta of react-native-snap-carousel. It's a lot less buggy and I had issues with using snapTo not focusing / animating when using version 3.9.1

Is it stable enough to be used in production? Would you recommend?

Seems solid enough based on the tests I've done (only Android 10 / Google TV). Not sure about tvOS (Apple). I did read a comment from the plugin author saying they were using it in production. It's up to version 6 of beta.

Awesome thank you! Im gonna try that. And also one quick question regarding the beta release you mentioned, is it possible to change the slide transition speed?

CyberCyclone commented 3 years ago

@jeffreyabarrios I don't think so. I can't see a prop for it, but it's not really something it can do anyway. The plugin is built on-top of Flatlist which is designed mostly for touch input. So the scroll speed would be based on the persons finger speed. If Flatlist doesn't support it, then this plugin can't support it.

CyberCyclone commented 3 years ago

Since I've found the above solution to be workable, I'm going to consider this closed.