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 ActivityIndicatorIOS doesn't hide initially #8134

Closed
wants to merge 6 commits into from

Conversation

redmar
Copy link
Contributor

@redmar redmar commented Jun 15, 2016

I used the reproducible steps as described in origin bug ticket #7987 as test plan.
This has the same contents as PR #8130 but then against master per @janicduplessis request.

@ghost
Copy link

ghost commented Jun 15, 2016

Thank you for your pull request and welcome to our community. We require contributors to sign our Contributor License Agreement, and we don't seem to have you on file. In order for us to review and merge your code, please sign up at https://code.facebook.com/cla - and if you have received this in error or have any questions, please drop us a line at cla@fb.com. Thanks!

@ide
Copy link
Contributor

ide commented Jun 15, 2016

Can you explain the root cause of the bug?

@ghost
Copy link

ghost commented Jun 15, 2016

Thank you for signing our Contributor License Agreement. We can now accept your code for this (and any) Facebook open source project. Thanks!

@ghost ghost added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Jun 15, 2016
@redmar
Copy link
Contributor Author

redmar commented Jun 15, 2016

Can you explain the root cause of the bug?

No not really 😞 , I've tried to trace diffs that relate to the ActivityIndicator but couldn't find the real origin.
I think @janicduplessis comment and idea how to fix in #7987 could be a pointer but am not deep enough into the core of iOS react native to give any sensible reason why the bug occurred.
Still curious about the root cause.

@janicduplessis
Copy link
Contributor

I know that calling stopRefreshing too early doesn't work, it's probably a but in UIKit, not sure exactly at what point does it start working but calling if after the first layout does the trick. My only concern is that I think it used to work at some point so I wonder what changed to break this.

@janicduplessis
Copy link
Contributor

@redmar Do you know if it is broken since a specific version or RN or did it never actually work?

@redmar
Copy link
Contributor Author

redmar commented Jun 18, 2016

@janicduplessis ok so this took me some time but I did a manual bisect of all the commits between 0.26 (good) and 0.27.0-rc (bad). I can pinpoint the bug to one specific commit now, even to 3 lines in that commit that enable it:

The commit where the bug is introduced is: fe5c0d2

and the 'offending' lines that enable the visibility of the ActivityIndicator while it should be hidden are:

if (view.isHidden != isHidden) {
view.hidden = isHidden;
}

when i comment those lines out everything is working fine.

@janicduplessis
Copy link
Contributor

Great job finding out the commit that broke this!

@rigdern Any idea on the best way to fix this?

@ide
Copy link
Contributor

ide commented Jun 19, 2016

@redmar thanks for tracking that down. I think what is happening is that when the ActivityIndicator is stopped (which is its default state), it also internally sets self.hidden = NO unless you tell it not to. But this behavior is not modeled in React nor the shadow views so we end up doing:

actualActivityIndicator.hidden = shadowView.hidden // YES

These are three possible solutions:

  1. Extend UIActivityIndicatorView and override setHidden to check hidesWhenStopped and isAnimating. This would make it so that we could never display a stopped ActivityIndicator, which on one hand is not very useful, but on the other, it is kind of lame to take away that flexibility unless we have to.
  2. Make shadowView.isHidden (
    [areHidden addObject:@(shadowView.isHidden)];
    ) a tri-state NSValue boolean: YES, NO, nil. Set view.hidden = isHidden only when isHidden != nil. This does add complexity (boo) and maybe perf overhead (boo, but need to profile).
  3. Break the implicit hidesWhenStopped behavior and make it so that if you want to hide the ActivityIndicator, you need to explicitly write <ActivityIndicator hidden /> in React.

Maybe there are more ideas but those are the ones I have.

@redmar
Copy link
Contributor Author

redmar commented Jun 19, 2016

@ide I think I got your first point working but without the catch of not being able to never display a stopped ActivityIndicator. See added commit.

Tested this on the test case and it seems to work 😄

edit: whoopsie a bit too fast, forgot to add the old animating custom view property code. Now back.

@janicduplessis
Copy link
Contributor

@redmar What if hidesWhenStopped is set to false, does it still work?

@redmar
Copy link
Contributor Author

redmar commented Jun 20, 2016

@janicduplessis

hidesWhenStopped={false} animating={false} => activity indicator initially shown but not animating
hidesWhenStopped={false} animating={true}  => activity indicator initially shown and animating
hidesWhenStopped={true} animating={true}  => activity indicator initially shown and animating
hidesWhenStopped={true} animating={false}  => activity indicator initially not shown (bug case, now working as expected)

AFAIK it all works as expected in these cases.

Current patched behaviour is now that when the 'offending' code (seen here

if (view.isHidden != isHidden) {
view.hidden = isHidden;
}
) wants to setHidden=NO on the activityindicator view because the shadowview didn't get the memo to be hidden (as @ide described) it checks again if it should be hidden or not. It has logic to watch for when hidesWhenStopped=TRUE and animating=FALSE it should be hidden no matter what. That's why it's now hidden in the bug case (expected behaviour).

All other interaction with the control is delegated to super so should still work as intended.

@janicduplessis
Copy link
Contributor

@redmar @ide What about we set the hidden value in ActivityIndicator.js?

Something like

hidden={this.props.hidesWhenStopped && !this.props.animating}

https://github.com/facebook/react-native/blob/master/Libraries/Components/ActivityIndicator/ActivityIndicator.js#L84

@redmar
Copy link
Contributor Author

redmar commented Jun 21, 2016

@janicduplessis have you tried this already? For me this doesn't seem to work, but maybe i'm doing something wrong. (used master, reproduced existing bug, and then applied your suggestion but i don't see any changes while i can confirm the code was really changed).

a possible reason for wanting to use the current patch (which now is only a couple of lines) is that it's an iOS bug only AFAIK so the fix also belongs to the iOS layer/space. But I'm pretty new to this repo so I'm not up to date yet with any policies about where to apply fixes or priority between JS or obj-c space. 😃

@@ -23,13 +23,30 @@ @implementation RCTConvert (UIActivityIndicatorView)

@end

@interface RCTActivityIndicatorView : UIActivityIndicatorView
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's move this to it's own file for consistency with other views / view managers.

@janicduplessis
Copy link
Contributor

Ok let's do it this way. It doesn't fix the root issue of showing a view that is hidden initialy but I think this is so specific that activityindicator is the only control that this can cause an issue so fixing it here is fine.

@redmar
Copy link
Contributor Author

redmar commented Jun 22, 2016

@janicduplessis committed changes based on your comments, hopefully i've done it all in the correct way. (changing and seeing the diff from those .pbxproj files always feels weird)

@janicduplessis
Copy link
Contributor

Thanks @redmar! Sorry for the delay, looks good, lets ship this.

@facebook-github-bot shipit

@ghost ghost added the Import Started This pull request has been imported. This does not imply the PR has been approved. label Jun 27, 2016
@ghost
Copy link

ghost commented Jun 27, 2016

Thanks for importing. If you are an FB employee go to Phabricator to review.

@JohnDotOwl
Copy link

How do I get this fix?
i'm on
"dependencies": {
"react": "15.1.0",
"react-native": "^0.28.0"
}

@redmar
Copy link
Contributor Author

redmar commented Jun 29, 2016

It's not yet in v0.29.0-rc.0 AFAIK so you have to wait on the next rc but you can use it now by using master temporarily in your package.json with the following:

"dependencies": {
  "react": "~15.2.0-rc.1",
  "react-native": "https://github.com/facebook/react-native.git"
}

Don't forget to run an react-native upgrade after doing npm install after changing your package.json 😄

@janicduplessis
Copy link
Contributor

It should be in the final 0.29 release but it is not in the current 0.29rc.

ide pushed a commit that referenced this pull request Jul 2, 2016
Summary:
I used the reproducible steps as described in origin bug ticket #7987 as test plan.
This has the same contents as PR #8130 but then against master per janicduplessis request.
Closes #8134

Differential Revision: D3491126

fbshipit-source-id: a22669dc998f82b36fbe31d882d0a29f0912e2ee
samerce pushed a commit to iodine/react-native that referenced this pull request Aug 23, 2016
Summary:
I used the reproducible steps as described in origin bug ticket facebook#7987 as test plan.
This has the same contents as PR facebook#8130 but then against master per janicduplessis request.
Closes facebook#8134

Differential Revision: D3491126

fbshipit-source-id: a22669dc998f82b36fbe31d882d0a29f0912e2ee
mpretty-cyro pushed a commit to HomePass/react-native that referenced this pull request Aug 25, 2016
Summary:
I used the reproducible steps as described in origin bug ticket facebook#7987 as test plan.
This has the same contents as PR facebook#8130 but then against master per janicduplessis request.
Closes facebook#8134

Differential Revision: D3491126

fbshipit-source-id: a22669dc998f82b36fbe31d882d0a29f0912e2ee
This pull request was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. Import Started This pull request has been imported. This does not imply the PR has been approved.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants