React-Native Blur Radius Animation with ScrollView is Choppy - javascript

I have a ScrollView using Animated Event to do some basic animations. Everything works great but now I am wanting to animate blurRadius on images but the blur doesn't kick in until a few seconds after scrolling began. I've tried just about every animation solution possible...
This is the ScrollView... (AnimatedEvent.scrollYOffset is just a shortcut function I made) (Normally I have the throttle at 16 but found 7 was a little better but not even close to good)
<ScrollView
onScroll={AnimatedEvent.scrollYOffset(animY)}
scrollEventThrottle={7}
style={[QuickStyle.fillScreen,{
backgroundColor: 'rgb(16, 50, 74)',
flex: 1,
}]}>
This is one of the images with the blur property...
const blurry = this.state.animY.interpolate({
inputRange: [0,150],
outputRange: [0,7],
extrapolate: 'clamp'
});
const slide1 = <View style={[{
borderRadius: borderRadius,
overflow: 'hidden',
width: width,
height: height,
backgroundColor: 'rgb(28, 181, 251)' //light blue
}]}>
<Animated.Image blurRadius={blurry} ref={img => this.blur1 = img} style={{
width: width,
height: height,
}} source={require('../../assets/images/big-numbers.jpg')} />
</View>;
What I've tried... (all with the same laggy choppy result) 1) Animating directly into the blurRadius prop 2) Using a ref with setNativeProps({blurRadius:x}) 3) Using setState({blurRadius:x}) - this was at least smooth but slowed down every animation a lot.
What I am trying next... Running these 3 solutions in release mode. I also will consider doing this directly in Objective-C, but really want to avoid that...
Would the react-native-blur package help? I'm guessing not...
Please help! Thank you!

I finally gave in and just put a BlurView from react-native-blur over what I wanted to blur. I then just animated the opacity and everything is smooth as can be.
The only problem is, it does not look as nice as blurring the image directly through blurRadius, but so far it's the only way I've been able to get this to work for now.
Please, if you have another solution, let me know!
UPDATE
Finally, I got this working without having to animate opacity on a react-native-blur BlurView! And it looks 10x better!
I am using the solution by #umitanuki from https://github.com/react-native-community/react-native-blur/issues/152
Here's how I did it...
Go to https://github.com/AlpacaDB/react-native-blur/tree/animate/ios
Set your BlurView.m in Xcode to exactly what the BlurView.m there has.
Use onScroll and setState to change the blurAmount property on a BlurView (react-native-blur).
This accomplishes the same effect as blurRadius but runs perfectly smooth when animating.
EXTRA
When using this solution I found one problem... When exiting the app and coming back to it (without fully quitting it), the blur goes away until you scroll again or do something to update it.
To solve this I went back into BlurView.m and added an observer for when the app becomes active...
[[NSNotificationCenter defaultCenter]addObserver:self
selector:#selector(appBecameActive)
name:UIApplicationDidBecomeActiveNotification
object:nil];
-(void) appBecameActive {
[self updateBlurEffect];
}
I then ran updateBlurEffect when the app became active. Unfortunately there was no way to solve this within react-native, but this works perfectly.

Related

Why do my elements flicker before an animation using css

I was creating a 2048 clone from scratch as a project. I have got the game pretty much working only problem is that my animations look janky. I have used css grid to construct my game board and after every move (user input) all the tiles are meant to slide across the board in a direction. That part works fine, it's when they start the slide animation that for whatever reason some of the elements flicker.
I'm not the best with css animations but I have tried to look at every resource I could and I couldn't find any solutions suited to my code. I tried switching the animation timing, delaying the animation etc to no avail. I did use a package animate-css-grid (because animating css grid is hard) which only handles the tiles sliding across the grid and I do not suspect that it is causing the issue.
I have put the code on js fiddle if anyone is interested to try and see the problem https://jsfiddle.net/codedjourney/uv1o48L6/3/ hello
Also if anyone has a better way of animating css grid let me know the package while helpful is a bit odd to work with. Thanks for the help
I managed to get rid of the flickering by commenting out the hidden class in the addTile method
addTile(tile) {
// create the tile
const tileElm = document.createElement("div")
tileElm.classList.add(
"cell",
"tile",
// "hidden",
`cell-${tile.x}-${tile.y}`
)
const valueElm = document.createElement("div")
valueElm.classList.add("tile-container", `value-${tile.value}`)
valueElm.textContent = tile.value
tileElm.appendChild(valueElm)
this.display.appendChild(tileElm)
this.cells[tile.x][tile.y] = new Tile(
tileElm,
tile.x,
tile.y,
tile.value
)
// request frame to allow transition to play
window.requestAnimationFrame(() => {
tileElm.classList.remove("hidden")
})
}
As I saw your code All I see is that it's getting larger while colliding and it's happening because you have added css the one which scales your box while colliding.
Transform: Scale
Try using this css style and you might get your problem solved.

Debounce jsx element's rendering in React

I am wondering if it is possible to debounce a jsx element's rendering. I have an animation of a panel expanding that has some content in it. If the panel is empty (just the background) the animation is smooth and works as expected. The animation and associated components are all from Material-UI. The issue arises when the content is in the panel already so the animation (width expansion) just skips out to the width of the content making the animation look choppy. Here is a similar example to what I am referring to. This code is my code I am using in my panel and they work the same in terms of the expansion. Only difference is the content in this example is just lorem ipsum so the animation appears to work fine. Is it possible to debounce the <CardContent /> component's rendering like this?
{ open &&
(
_.debounce(e => {
return (
<CardContent>
{/*content in here*/}
</CardContent>
)
}, 300)
)
}
or something similar (this doesn't work) so the panel will be fully expanded through the animation before the content is rendered?
I'd like to add a comment however my reputation isn't above 50 yet so unfortunately I can't :p.
JS Animation
To answer your question, if you are using JavaScript animations like GSAP or AnimeJS you can have a state flag called. isAnimating = null. Then when your animation starts set the flag to true and when it's finished set it to false. Then in your render() method write a conditional render like this.state.isAnimating === false && <CardContent />.
CSS Animation
If you are using CSS animation you can use the transitionend event to wait for the animation to end. Therefore you have to create a ref on the animating DOM element to which you can attach the event.
Does that help you a bit? Please let me know if you have any other questions.
Here is a solution using react spring library
I added a state variable in order to display or not the card content
const [contentVisible, setContentVisible] = React.useState(false);
I created a spring to handle the width transition, I set contentVisible to true as soon as the width approaches the 300
const { width } = useSpring({
width: open ? 300 : 120,
onFrame: ({ width }) => setContentVisible(width > 299.8)
});
Finally, I created an animated card component
const AnimatedCard = animated(Card);
...
<AnimatedCard classes={{ root: classes.card }} style={{ width }}>

WinJS enterPage animation not working as expected

I wanted to add animations to my app on page enter, and hooked with the default WinJS.UI.Animation.enterPage(element), and that worked fine sliding in the element from right to left.
I need to slide it from bottom (100px) to top. Once I overrode the default values with WinJS.UI.Animation.enterPage(element, { top: "100px", left: "0px" }) I saw no animation at all on my screen which is weird.
However when coupled with WinJS.UI.Animation.exitPage(oldElement), the animation seemed to work but I wanted to further tweak the timing.
following as per https://msdn.microsoft.com/en-us/library/windows/apps/Dn127042(v=win.10).aspx#creating_custom_animations, didn't help. After using the example from "Combining custom animations and transitions" in the link, I could see only the opacity changing and the element fading in, however no translation at all. I tried the same pairing with WinJS.UI.Animation.exitPage(), and adding my own customExitPage - basically using from WinJS, and with just opacity... and nothing just works.
I was referring to some of the animation implementations from here as well -
https://github.com/winjs/winjs/blob/ad8691b3d5227ff1576a5d2a90a42f022498d2a9/src/js/WinJS/Animations.js, to get control over the timing.
Anyone else having this issue? or am I doing something wrong... or is it WinJS behaving bad?
EDIT:
weirdly enough the "to top" animation with enterPage(element, {top: "100px", left: "0px"}) started working. However the custom animation still remains elusive.
well, I was able to finally figure out the "weird behavior". The #keyframes should have been set in CSS, and I was trying a few other things and apparently that's the reason that it didn't work.
However, I would probably say the explanation could have been a little more clearer in the site as well.
when we are already providing the from - to values in the javascript, I would otherwise about providing the same again as part of CSS too which is still weird.
Like mentioned in the site,
add this to css: #keyframes custom-translate-in { from { transform: translateY(50px); } to { transform: none; } }
and have this in js:
function runCustomShowStoryboard() {
return WinJS.UI.executeAnimation(
target,
{
keyframe: "custom-translate-in",
property: "transform",
delay: 0,
duration: 367,
timing: "cubic-bezier(0.1, 0.9, 0.2, 1)",
from: "translate(50px)",
to: "none"
});
}
Never was able to figure out why and how the "bottom to top" animation started working (probably restarting visual studio helped)

Javascript/jQuery slowdown when switching to full screen

I have some strange behavior from firefox, I'm building a single page portfolio and as a graphic designer the coding has been hard. I wanted to smoothly control the navigation and then later added scaling to all the elements (designed for 1920x1080 full screen initially). The lecturer dropped a bomb that it needed to scroll vertically as well, I am in the process of trying to get the vertical navigation to work.
The issue is when I switch to full screen most of the navigation code seems to take a long pause before it executes. This only happens when I switch to full screen. If I switch and refresh then it's ok. I really want to know whats slowing the whole thing down.
I have tried safe mode with no plugins. I'm using Firefox 24.0 with Firebug to get at the bits an pieces.
I have created a code fiddle (my first and it's already broken):
http://jsfiddle.net/jeffreyknipe/xfjmC/1/
The code for the scrolling is as follows:
function navTo(horizontal, vertical) {
browserWidth = $(window).innerWidth();
browserHeight = $(window).innerHeight();
newRatio = browserWidth / 1920;
$('html body div#full_site section#pages_section').animate({
marginLeft: '-' + browserWidth * horizontal,
marginTop: (browserWidth / 16 * 9) * vertical
}, 1000);
if (horizontal == 0) {
$('#menuspace #floating_topbar #menuzone').animate({
marginRight: 0
});
} else {
$('#menuspace #floating_topbar #menuzone').animate({
marginRight: (newRatio * (-340))
});
};
};
I know the coders out there will frown on how inefficient the code is but any advice will be appreciated. The biggest thing is the full screen code slow down.
Thanks.
The issue came in when animating the changes in items or location when going to and from full screen. I switched to setting the new values with .css rather than .animate (I did want it to animate to the new location) but since animation here wasn't a deal breaker and it solved the issue I'm a happy camper.
I have to assume that it wants to animate but the java script engine or some thing in Firefox get too busy during the change, it's almost a bug but I can't isolate whats happening while the script is jammed so I can't report it.

jQuery animate problems

I use the following snippet to make an element's background lightblue, then slowly fade to whiite over 30 seconds:
$("#" + post.Id).css("background-color", "lightblue")
.animate({ backgroundColor: "white" }, 30000);
Two questions.
First, instead of fading to white, is there a way to fade opacity to 100%? That way I don't have to change "white" if I choose to change the page's background color?
Second, about once out of every 10 or 15 times, the background stays lightblue and fails to fade to white. I'm using the latest versions of jQuery and the UI core. What could be going wrong?
EDIT: Bounty is for a solution to problem regarding second question.
EDIT2:
Apparently I got downvoted into oblivion because I said I rolled my own solution but didn't show it. My bad. I didn't want to be self-promoting. My code works 100% of the time and doesn't require jQuery. A demonstration and the code can be found at:
http://prettycode.org/2009/07/30/fade-background-color-in-javascript/
For your second question: in my experience this is usually because a Javascript error has occurred somewhere else on the page. Once there is one Javascript exception, the rest of the page stops running Javascript. Try installing Firebug (if you haven't already), then open up the "Console" tab and enable it. Then any javascript errors or exceptions will be printed to the console.
Another thing to try (which kinda contradicts my last statement...) is to disable all your browser plug-ins to see if you can recreate. Sometimes they interfere with scripts on the page (particularly GreaseMonkey.)
If you could provide a sample HTML snippet which reproduces this animation problem it would be a lot easier for us to help you. In the script I have pasted below, I can click it all day, as fast or slow as I like, and it never fails to animate for me.
For the first question: I know you said you'd found a workaround, but the following works for me (even on IE6) so I thought I'd post it, since it may be different from what you were thinking. (Note that setting CSS "opacity" property through jQuery.css() works on IE, whereas IE does not support the "opacity" property directly in CSS.)
<html>
<head>
<style>
body { background-color: #08f; }
#test { background-color: white; width: 100px; }
</style>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script>
var myOpacity = 0.125;
$(function(){
$('#test').css('opacity', myOpacity);
$('a').click(function(){
myOpacity = 1.0 - myOpacity;
$('#test').animate({ opacity: myOpacity });
return false;
});
});
</script>
</head>
<body>
<p>Click me</p>
<div id="test">Test</div>
</body></html>
Dont forget the color plugin.
See here
When the color fails to animate to blue you could try to use the callback function to log a message to the console. You can then check that the event actually fired and completed. If it does then you could potentially use two animates. The first one to animate to a halfway house color then the use the callback to animate to white (so you get two bites of the cherry, if the outer fails but completes the callback has a second go)
It would be good if you could try to recreate the issue or give a url of the issue itself.
e.g
$("#" + post.Id).css("background-color", "lightblue")
.animate({ backgroundColor: "#C0D9D9" }, 15000, function(){
$(this).animate({ backgroundColor: "#ffffff" }, 15000)
});
You could always use something like this, avoiding the JQuery animate method entirely.
setTimeout(function() { UpdateBackgroundColor(); }, 10);
UpdateBackgroundColor() {
// Get the element.
// Check it's current background color.
// Move it one step closer to desired goal.
if (!done) {
setTimeout(UpdateBackgroundColor, 10);
}
}
Also, you may be able to remove the "white" coding by reading the background color from the appropriate item (which may involve walking up the tree).
It is possible to have jQuery change the Opacity CSS property of an item (as mentioned in another answer), but there's two reasons why that wouldn't work for your scenario. Firstly, making something "100% opaque" is fully visible. If the item didn't have any other modifications to its opacity, the default opacity is 100%, and there would be no change, so I'm guessing you meant fading to 0% opacity, which would be disappearing. This would get rid of the light blue background, but also the text on top of it, which I don't think was your intent.
A potentially easy fix for your situation is to change the color word "white" to "transparent" in your original code listing. The color plugin may not recognize that color word (haven't checked documentation on that yet), but setting the background color to "transparent" will let whatever color behind it (page background, if nothing else) shine through, and will self-update if you change your page background.
I'll answer your first question.
You can animate opacity like this:
.animate({opacity: 1.0}, 3000)
I think you can try using fadeOut/fadeIn too..
What about:
$("#" + post.Id).fadeIn( "slow" );
You could possibly have two divs that occupy the same space (using position: absolute; and position: relative; setting the z-index on one higher to make sure one is above and the other is below. the top one would have a transparent background and the one below would have a background color. then just fadeout the one below.
As for the second question:
If you think the default animation classes from JQuery are not properly working you could try Bernie's Better Animation Class. I have some good experiences with that library.
Animate only works for numbers. See the jquery docs. You can do opacity but you can't do background color. You can use the color plug in. Background-color uses strings like 'red', 'blue', '#493054' etc... which are not numbers.

Categories