How to: Animate 9gag's "add button" by using React Native - javascript

So I wanted to challange myself and try to implement the blue button from 9gag which allows you to add content. Its on the right bottom cornern and every time you scroll down and reach a specific "speed" it disappears. And when you scroll up again, it appears again until you scroll down again with that specific "speed". I tried my best but couldnt make it. Here is the link to the video how it should look:
https://www.youtube.com/watch?v=ieT4hZJST5I&feature=youtu.be
So far I was able to make that button on the right postion. But I dont know how to change his visibility onScroll:
<TouchableOpacity
activeOpacity={0.6}
style={{
position: 'absolute',
right: addContentButtonRight,
bottom: addContentButtonBottom,
opacity: addContentButtonOpacity
}}
// onPress={this.onAddPress}
>
<Image style={{width: 65, height: 65}} source={iconSource} />
</TouchableOpacity>
And this here is what was my idea for it:
//using state to be able to update opacity
const [addContentButtonOpacity, setAddContentButtonOpacity] = useState(1);
//when the scrollView is scrolled I would call this function with onScroll().
//It sets the new value to opacity by using opacity - 0.1
//In this way the further you scroll, the more invisible it bacomes
const addContentButtonOpacityChange = () => {
setAddContentButtonOpacity(addContentButtonOpacity-0.1);
}
And also if this would work and my button becomes invisible, how would I make it not touchable so that the invisable button cant be clicked by mistake/randomly?
Any idea how to implement this?

Related

React Bootstrap- Overlay Tooltip rendering in wrong position initially

I am writing a react bootstrap app where a button appears at the end of an animation. When the button first appears, I want a tooltip to appear next to it. Once the user hovers over and off the button, the tooltip should go away and re-appear whenever the user hovers over the button again. I've gotten this to work as desired, but when I position the button where I want it to be (fixed to the bottom of the screen), the tooltip initially renders in the wrong position (where the button was before being positioned).
I have created two simple examples to demonstrate this behavior.
In the first example, the button is positioned at the top of the screen and the tooltip behaves as this desire:
function Testing(){
const refLink = useRef(null);
const [overlayOpen, setOverlayOpen] = useState(true); // Initially open
const [textDone, setTextDone] = useState(false);
useEffect(() => {
const timeoutId = setTimeout(() => {
setTextDone(true)
},1000)
return () => clearTimeout(timeoutId)
},[])
return(
<Container>
<Row>
{textDone ?
<>
<Button ref={refLink} onMouseOver={() => setOverlayOpen(true)}
onMouseOut={() => setOverlayOpen(false)}
>
<FaComment/>
</Button>
<Overlay target={refLink.current} show={overlayOpen}
onHide={() => setOverlayOpen(false)} rootClose placement={"bottom"}>
<Tooltip>
Submit a personal response!
</Tooltip>
</Overlay>
</>
: ''
}
</Row>
</Container>
)
}
export default Testing
The textDone state is set to true once the "animation" finishes. To simplify the example, I omitted the animation itself and recreated the delay with setTimeout.
The second example is identical except for the following .css class added to the Row element in which the button, overlay, and tooltip are nested inside of.
.fixed-button{
position:fixed;
right: 20px;
bottom: 20px;
}
With this addition, the button ends up where I want it, but the tooltip first appears at the top of the screen. Once I hover over the button, the tooltip moves to the correct position.
Here are some gifs of the two examples.
Example 1 (tooltip behaving as intended but button not positioned in right spot)
Example 2 (button positioned where I want it but tooltip initially showing up in wrong spot)
My question is: how can I get the tooltip to initially appear in the correct position?

How to use animation multiple times in framer motion

Just like in the title, I'm trying to animate my component multiple times when clicking a button. Currently, animation only runs once and then it doesn't work anymore, how could I possibly implement that
here is an example of what I'm trying to do:
const controls = useAnimation();
const handleClick = (e) => {
controls.start({
rotate: "360deg",
});
};
return(
<motion.button onClick={handleClick}>Button</motion.button>
<motion.div className="someRect" animate={controls}></motion.div>
)
To be honest, I've never worked with useAnimation controls so I have no idea what's going on here and how to come around this obstacle using your approach, but you may achieve what you are after with something like this.
<button onClick={() => setRotate((prevState) => prevState + 360)}>
Button
</button>
<motion.div
className="someRect"
animate={{
rotate: rotate,
transition: { duration: 3 }
}}
style={{ width: "100px", height: "100px", background: "red" }}
>
</motion.div>
I know that this solution is not optimal as the state is growing and growing with each click to possibly very substantial size which may cause problems at some point.
Check my solution in this CodeSanbox
Hope maybe someone will come up with a much more elegant solution which I'd appreciate seeing too.

How to rebuild the iOS Picker animation in React Native

Is there a way in React Native to rebuild the iOS picker component completely in Java Script? I don't need the common picker, but a normal scroll view with a similar fade-out effect like the iOS picker.
EDIT – I think I have not explained my initial answer exactly enough. This is why I complete it here:
I want to build a scroll view that takes over the whole screen. It's not supposed to give the user the possibility to elect some item, like the the iOS Picker does. Nevertheless, it's supposed to be a 'normal' scroll view, that shows the user some information, e.g. different chats, tasks, news and so on.
The only difference to React Native's common scroll view should be the fade-out effect at the top: When the user scrolls the content up, it should not just leave the screen at its top edge, but it should use the iOS Picker's fade-out effect (see picture).
This fade-out effect is made up of two parts: First of all, it raises the content's transparency with a decreasing y-coordinate. Furthermore, this content seems to escape into the third dimension.
My problem is, that I don't see a way to achieve this three-dimensionality of the content in React Native. I've to add, that the content in my scroll view does not consist of small, equally sized items (like e.g. the texts 'Item 1', 'Item 2', 'Item 3',...), but of bigger items with different sizes like images or whole textboxes.
You can use this NPM module to get what you want. That module works the same in Android and iOS. Do not reinvent the wheel :)
EDIT: Now I've understood what you want. You can try this snack that I've made for you:
https://snack.expo.io/r1qnxSt9m
Of course you need to improve it, but it's a beginning.
You can achieve the desired effect with the Animated api. The idea is to set different input ranges to the items in your list. You then hook the opacity to the scroll value of your ScrollView (or any list component). I have simplified the code, but it should be enough to demonstrate the idea.
The example below only demonstrates an opacity effect, but you could easily add a translate effect to get the exact animation that you are looking for.
const data = []; // array that contains the text
const items = [];
for (let i = 0; i < data.length; ++i) {
const distanceFromViewCenter = Math.abs(i * ITEM_HEIGHT);
const inputRange = [
-distanceFromViewCenter - 2 * ITEM_HEIGHT,
-distanceFromViewCenter - ITEM_HEIGHT,
-distanceFromViewCenter, // Middle of picker
-distanceFromViewCenter + ITEM_HEIGHT,
-distanceFromViewCenter + 2 * ITEM_HEIGHT,
];
items.push(
<Animated.View
style={{
opacity: this._scrollValue.interpolate({
inputRange,
outputRange: [0.0, 0.3, 1.0, 0.3, 0.0],
}),
}}
>
<Text style={{ height: ITEM_HEIGHT }}>{data[i]}</Text>
</Animated.View>
)
}
<ScrollView
onScroll={Animated.event(
[{ nativeEvent: { contentOffset: { y: this._scrollValue } } }],
{ useNativeDriver: true }
)}
>
{items}
</ScrollView>

How to add text to an image in React Native?

I'm researching if it is easily possible with React Native or whether I should build a native app.
I want to edit an image from the photo library and add a text overlay to it. Think of it like a postcard with a greeting message on it.
How would I add text to and image and make a new copy of it in react native? I'm not looking for detailed code, just for an explanation on how to get started.
Update:
Would it be a good alternative to just save the coordinates of the message on the picture instead of generating a new image?
You can go with 2 ways. You can either render the text on an image component and save the position of that text or you can process the image and get a new image with the text.
The first option brings up the problem of that position is relative to image's size. Means that if the image renders on a different sized screen the position and size of text should also be moved accordingly. This option needs a good calculation algorithm. Also, another problem could be the rendering times. Text component will render instantly but Image component needs to load the image first. This option also needs a good way of render algorithm.
The second option is not possible without a 3rd party library or some level of native code since react-native doesn't support image processing beyond the limits of CSS. A good and maintained image processing library is gl-react-native-v2. This library helps you to process and manipulate the image as you wish and then save the result with captureFrame(config). This option is more capable of processing file but needs you to save a new image.
Either way is good if the way you go is appropriate for your use case. The decision really depends on your case and preference.
You could use react-native's ImageBackground tag since using the Image tag as a container would give you a yellow box warning.
The sample code for it with overlay is as shown below
<ImageBackground source={SomeImage} style= {SomeStyle} resizeMode='SomeMode'>
{loader}
</ImageBackground>
It would be efficient if you work on the same image by changing the flex property in the styles of the image or you may set the position: absolute to the main image container and assign top , bottom, left, right to the nested container.
Helpful link may be found here
<View style={{flex: 1, justifyContent: 'center', alignItems: 'center', marginTop: 20}}>
<Image
style={{
flex: 1,
width:100,
height:100,
}}
source={require('../imgs/star.png')}
/>
<Text style={{position: 'absolute', fontSize: 20}}>890</Text>
</View>
I'm researching if it is easily possible with React Native or whether I should build a native app.
This sounds very doable in react-native
I want to edit an image from the photo library and add a text overlay to it. Think of it like a postcard with a greeting message on it.
I think I would capture ALL the relevant metadata as an object...
{
image: {
uri: './assets/image.jpg',
height: 576,
width: 1024
},
message: {
fontFace: 'Calibri',
fontSize: 16,
text: 'Happy Holidays!'
boundingBox: {
height: '30%',
width: '30%',
top: 0,
left: 0
}
}
}
With the above detail (and maybe more), you'd then be able to reconstruct the design intent on any device, regardless of size (tablet vs mobile) or pixel depth. The boundingBox would be expressed in terms relative to the image's rendered dimensions. In the above example, the message would be contained in a text box no more than 30% of the image width, 30% of its height, and positioned in the top-left corner.
How would I add text to an image and make a new copy of it in react native?
This eliminates the need to do any screenshotting or actual image manipulation, etc. No need to "make a new copy". Just treat them as two separate and distinct assets, then merge them at render using the metadata you captured.
Final thought: if you "need" to "upload the finished photo to a server" as you stated in another comment to another solution, you can do this serverside using any number of technologies using the metadata as your guide.
You can use position: absolute since adding children to Image is deprecated. Following code will align text in middle (vertically and horizontally) over the image:
<View>
<Image
source={yourImageUrl}
resizeMode={'cover'}
style={{
width: 300,
height: 300
}}
/>
<View style={{ position: 'absolute', top: 0, left: 0, right: 0, height: 300, alignItems: 'center', justifyContent: 'center' }}>
<Text>Your overlay text</Text>
</View>
</View>
If you need to only show a text over the image you can wrap the image in a view and after the image insert a text element with position: 'absolute'. If you want a copy of the image containing the text then you can use the same approach but take a snapshot using react-native-view-shot
As far as I know, the image component can be used as a container so you can do something like this:
<Image>
<Text>{"some text"}</Text>
</Image>
Below code is what I used to add text on image at particular coordinates on image.
Xcode 8.3.2 Swift 3.1
func textToImage(drawText text: NSString, inImage image: UIImage, atPoint point: CGPoint) -> UIImage {
let textColor = UIColor.white
let textFont = UIFont(name: "Helvetica Bold", size: 10)!
let scale = UIScreen.main.scale
UIGraphicsBeginImageContextWithOptions(image.size, false, scale)
let textFontAttributes = [
NSFontAttributeName: textFont,
NSForegroundColorAttributeName: textColor,
] as [String : Any]
image.draw(in: CGRect(origin: CGPoint.zero, size: image.size))
let rect = CGRect(origin: point, size: image.size)
text.draw(in: rect, withAttributes: textFontAttributes)
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage!
}
And call above method as below
let imageWithText = textToImage(drawText: "textOnImage", inImage:yourImage, atPoint: CGPoint(x:9,y:11))
There are several libraries available for that. If you want to add a text to an image you can use: react-native-media-editor. This is quite a good option for adding text to an image but I recommend you react-native-image-tools. It provides so much flexibility. You can add a text and position it accordingly. Apart from that, there are filters, cropping option, light adjustments and so much more.
It depends on the use case but if you simply want to put a text on an image, using ImageBackground is a one of the good approach.
Do it like below.
<ImageBackground
source={{ uri: hoge }}
style={{
height: 105,
width: 95,
position: 'relative', // because it's parent
top: 7,
left: 5
}}
>
<Text
style={{
fontWeight: 'bold',
color: 'white',
position: 'absolute', // child
bottom: 0, // position where you want
left: 0
}}
>
hoge
</Text>
</ImageBackground>

Not sure what affecting button display - updated

I have and radio button selection and given each radio button a progress bar, progress bar are display:none but when selected a radio progress bar will show(), same to the button.
Now my problem is sometime when I selected a radio button, the button show like this:
But sometime when I selected a radio button, the button has been push to the bottom and cant even seen:
I not sure where this problem come from, but I guest maybe the progress bar blocked it?
Maybe I have miss something in my code that I don't know. Anyone able to help me check for this problem ?
Click here for jsfiddle
Updated part
I found out how to make the button push to bottom , hover in and hover out the div 4 to 5 times then select one option, then the button will push to bottom. So far haven't found any solution, anyone know how to fixed please help. Thanks a lot.
Remove the margin-top: -22px from .popup_survey_whitebox_percent and replace with
position: relative;
top: -22px;
Fiddle
Finally I found a way to fixed this problem .
$("#popup_survey_whitebox").hover(function () {
$('#popup_survey_whitebox_content').finish().animate({
opacity: 1,
height: "toggle"
}, 500, function () {
$("label#popup_survey_label_title").text(orig); // Here put the original text.
}).css('position', 'relative');
}, function () {
$('#popup_survey_whitebox_content').finish().animate({
opacity: 1,
height: "toggle"
}, 500, function () {
$("label#popup_survey_label_title").text(newText); // Here put the new text with "..."
}).css('position', 'relative');
});
change $('#popup_survey_whitebox_content').stop() to $('#popup_survey_whitebox_content').finish() for both animate
As you mentioned in your answer, finish works, but introduces some quirkiness for the experience if you hover in/out quickly (it jumps to the end of the animtation immediately, and can "flicker").
This issue can be addressed by reseting the height attribute on the hover 'out' logic. When you hover in/out quickly, the height value is set, which is then used after.
Here's a fiddle with the fix: http://jsfiddle.net/v07vt9gz/5/
And the logic:
$(this).css('height', ''); // reset value

Categories

Resources