-
Notifications
You must be signed in to change notification settings - Fork 4.6k
[RNMobile] Scroll to selected block that goes off the screen #26596
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
Conversation
|
|
||
| // this adjustment factor is utilized to create an invisible bounds at the top and bottom of the screen where once the View enters within | ||
| //any of these bounds then the scrolling action is triggered. | ||
| const scrollAdjustmentY = isIOS ? 200 : 100; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am always concerned about hardcoding these types of values because I am not sure if they will support every screen size. I haven't done a thorough test on multiple screen sizes as yet as I wanted to get some opinions on the proposed solution here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I ended up going for a more dynamic solution using the window's height. Done here
| setListRef( ref ) { | ||
| this.listRef = ref; | ||
| } | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this being used?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It was being used before but not anymore. I will remove it 🙏
| * External dependencies | ||
| */ | ||
| import { FlatList } from 'react-native'; | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure if this line being removed was intentional, the codebase seems to use an empty line in these situations (it would be nice though to have a linter rule to ensure consistency, but that's another topic).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for spotting. I will remove it.
| export const KeyboardAwareFlatList = ( props ) => { | ||
| return ( | ||
| <KeyboardAvoidingView style={ { flex: 1 } }> | ||
| <FlatList ref={ props.listRef } { ...props } /> | ||
| </KeyboardAvoidingView> | ||
| ); | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm curious, what was the reason for changing the lines surrounding <FlatList ref={ props.listRef } { ...props } />? It seems the other lines changed, but are not directly relevant to the PR. Was it due to a formatting change that the editor did on save?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it seems the editor probably formatted this. I will revert this and I will be mindful of it in other PRs 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense, I've had some formatting issues with the editor too.
| ( _x, _y, blockWidth, blockHeight, px, py ) => { | ||
| const window = Dimensions.get( 'window' ); | ||
|
|
||
| if ( isSelected ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like this can be moved up to the beginning of scrollToSelectedBlockIfItsNotVisible to a) avoid execution reaching here if there's no selected block and b) reduce the number of levels of indentation.
scrollToSelectedBlockIfItsNotVisible() {
const { isSelected } = this.props;
if (!isSelected) return;
...
| scrollToSelectedBlockIfItsNotVisible() { | ||
| const { isSelected } = this.props; | ||
|
|
||
| if ( this.blockRef.current ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a nitpick: this could be changed to if ( !this.blockRef.current ) return; to reduce the number of levels of indentation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for this. I did it this way because that's the way how I wrote code in Kotlin in WPAndroid and the linter would throw an error if I did this without the braces 😅
guarani
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks really good! I think the approach is very solid too.
I noticed this strange glitch on iOS, it's hard to see what's happening in the gif below, so here's the steps to reproduce:
- Scroll down to the bottom of the gallery block in the demo content
- Tap the bottom of the gallery block
- Notice the editor jumps up to near the top of the content
I noticed you talked about issues with really large blocks, so maybe this is related. I couldn't reproduce with the current WPiOS build, so it looks to be related to these changes. Can you reproduce it?
![]() |
|---|
Thanks for the review @guarani 🙇
Yes, this issue the same as the one I described in the PR. I am going to see what I can do to resolve it. Do you have any thoughts about this comment :
I am wondering how we can determine how the block list |
|
One option could be to create a separate RN project and try to reproduce this behavior with a scrollable list of "blocks", that could help with determining if the issue is related to the virtualization of lists or something else. |
Thanks, @guarani that's a really good idea! Locally, I came up with a fix that would start the scroll again if the block isn't actually on the screen after a delay. So it would scroll to the next page, realize the block isn't there and then scroll to the actual block position. ( This is necessary because it seems the Flat List only loads items for one screen ahead - I haven't investigated this as yet but these assumptions are what led to the solution I'm mentioning now.) So far, I am thinking this might not be an optimal solution but in the interest of HACK week, I was wondering if it would be a sensible improvement because currently the block just goes off the edge which isn't good. Also, most users will not have blocks taking up the entire screen so it might be a justified compromise if no other solution is found. Wdyt? |
|
The only I found with my local solution/fix for this large black problem is that sometimes when the scroll is completely the block would be close to the end of that screen and a third scroll would be started so I need to modify the scroll logic a bit to ensure that the |
I could take a look if you'd like, feel free to push the commit up.
Yeah, I agree that most users won't have really long blocks. Is your preference to go forward with the latest code that you have on this PR (the code that I looked at already), or would you like to add the changes from your local test and I could take a look at that? I also agree that even if the solution is not perfect, if it's a good improvement we can ship it. |
Thanks for the feedback Paul! The solution I have isn't finished as yet but I am going to see if I can add in a final piece soon once I wrap up some other tasks on my list so we can ship this because it's a good improvement so far. It's buggy so I prefer to iron them out before pushing so you can be of more help 😄 |
This current solution involves checking if the py value of the yOffset passed will be within the bounds of any of the off screen bounds that's defined and if so then the yOffset being used to scroll needs to be readjusted to be within those bounds so another scroll isn't triggered. We are utilizing the height of the Flat List container to determine how the scroll view is divided based on the list's height.
|
Hi @guarani just an update here. I pushed some code that I was working on for the issue but it doesn't work as well I intended it to. I am going to revisit this task at a later time and once I am able to get it to a good place that doesn't have any bugs, at that point I will ping you for a follow-up review. Thanks for your help so far. 🙇 |
Sure, no worries! Anytime |

Fixes wordpress-mobile/gutenberg-mobile#735
Gutenberg Mobile PR wordpress-mobile/gutenberg-mobile#2771
Description
This solution seeks to address the issue where a block may get cut off due to it being moved off the edge of the screen. In a nutshell, whenever the selected
BlockListItemcomponent (which is a parent component for rendered blocks) is updated then we check to see if this list item is within the current viewport and if not we are utilizing the underlying scroll behavior for the respective Lists on each platform to reposition that item on the screen.How has this been tested?
To test follow the instructions below.
Screenshots
Below are two gifs of the functionality in action on Android and iOS
Moving a block off screen will auto-scroll the editor on Android
Moving a block off screen will auto-scroll the editor on iOS
Types of changes
The main tenets of the solution are as follows :
measuremethod of theViewcomponent is being utilized to determine the width, height, and position of the view within the current page/screen.measureLayoutmethod of theViewcomponent detects where within theFlatListthe currentBlockListItemexists so that we can utilize it'syposition for scrolling behavior.FlatList's scroll functionality on iOS is managed by theKeyboardAwareFlatListso the ref to it's underlyingScrollViewwas utilized while on Android, scrolling was accomplished using theFlatListcomponent itself.BlockListItemis within the window/screen we check to see if thepageYvalue is below zero ( which means we would need to scroll up) or above the window height ( which means we would need to scroll down)scrollAdjustmentYin the scroll algorithm. This is to give theBlockListItemthe ability to initiate scrolling without it's bottom or top being at the edge of the screen. This is also used within the calculation of the offset to scroll to so that we don't have an issue where we scroll to the bottom or top of a view and there's no space above or below the block.Concerns
Below you will observe that the list scrolls but it stops on the screen with the block that has taken up the entire viewport.
You will also observe the same behavior when trying to scroll up with the block up movement action. The block is not scrolled to. The list stops the scroll action on the part of the page with the larger block.
I am wondering if this is being caused because a
FlatListisVirtualizedso the scroll is faster than the fill rate of the content being rendered asynchronously off-screen. If so, then probably a delay could be introduced to ensure the list has rendered or we would have to somehow extend the off-screen limit in some way. Another approach would be to have some form of timeout/flag mechanism that runs a check to see if the block is within the viewport after the scroll has completed and if not then it does another scroll to the position it was supposed to scroll to in the first place.Checklist: