React Native - Move Button on Tap - button

I'm new to React Native (experiences iOS developer in Swift) and I can't seem to find anything online for how to move UI elements in response to touch events. (Or maybe I'm just really bad at searching stack overflow lol).
Eventually, I want to have a textbox in the center of the screen, and when the user begins to type (or taps on the box to start typing), the box will slide to the top of the screen. However I can't even find a simple tutorial for this. I know that I can have a const style that defines style/position aspects of the textbox, and I can create a second style and then on button tap I can change the textbox's style and re-render, but it seems overkill to make an entire second style, where only one attribute is changing.
Can someone provide sample React Native code, where there is a text label and a button on the screen, and when the user taps the button, the label moves from above the button to below the button?

Check out this example of moving an element on touch. I use a <TouchableWithoutFeedback> and onPressIn. When you touch it, it changes the x and y position of it:
https://snack.expo.io/#noitsnack/onpressin-twice
import React, { Component } from 'react';
import { Text, View, TouchableWithoutFeedback, Image, Dimensions } from 'react-native';
import IMAGE_EXPO from './assets/expo.symbol.white.png'
const IMAGE_SIZE = 100;
export default class App extends Component {
state = {
score: 0,
...getRandXY()
}
render() {
const { score, x, y } = this.state;
return (
<View style={{flex:1, backgroundColor:'steelblue' }}>
<Text style={{fontSize:72, textAlign:'center'}}>{score}</Text>
<TouchableWithoutFeedback onPressIn={this.addScore}>
<Image source={IMAGE_EXPO} style={{ width:IMAGE_SIZE, height:IMAGE_SIZE, left:x, top:y, position:'absolute' }} />
</TouchableWithoutFeedback>
</View>
)
}
addScore = e => {
this.setState(({ score }) => ({ score:score+1, ...getRandXY() }));
}
}
function getRandXY() {
return {
x: getRandInt(0, Dimensions.get('window').width - IMAGE_SIZE),
y: getRandInt(0, Dimensions.get('window').height - IMAGE_SIZE)
}
}
function getRandInt(min, max)
{
return Math.floor(Math.random()*(max-min+1)+min);
}
Once you get this movement down you can move to the Animation API to get teh sliding effect.

Related

Changing react-leaflet map width with button click

I am working on a map with react-leaflet. I placed a button on the map that will ideally open a menu on the left side of the map. The way I want to open up the menu is by changing the width of the map from 100% to 80%. The menu button toggles a boolean, which ideally the map will rerender and resize when the button clicks.
this is the code in my App.js
export default function App() {
const [isMarkerClick, setIsMarkerClick] = React.useState(false);
const [isMenuOn, setIsMenuOn] = React.useState(false);
function toggleMarker() {
setIsMarkerClick(prevClick => !prevClick);
}
function toggleMenu() {
setIsMenuOn(prevMenu => !prevMenu);
}
return (
<div>
<MainMap isMenuOn={isMenuOn} />
<MarkerButton isMarkerClick={isMarkerClick} toggleMarker={toggleMarker} />
<MenuButton toggleMenu={toggleMenu} />
</div>
)
}
this is where the Map Code lives
export default function MainMap(props) {
const isMenuOn = props.isMenuOn;
const isMarkerClick = props.isMarkerClick;
const zoom = 15;
const position = ['39.9526', '-75.1652'];
const [marker, setMarker] = React.useState(["", ""])
return (
<div>
<MapContainer
center={position}
zoom={zoom}
zoomControl={false}
style={{
height: "100vh",
width: isMenuOn ? "80vw" : "100vw"
}}
>
<TileLayer
attribution='© OpenStreetMap contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
<Marker position={marker}></Marker>
{isMarkerClick && <ClickTrack setMarker={setMarker} />}
</MapContainer>
</div>
)
}
as of now, when I click the menu button, the isMenuOn state updates and which then feeds back into the MapContainer and should rerender with a new width but it doesn't. Any Ideas on how to get change the map size with a click of button using react?
example of the menu button
I thought that when clicking the menu button and changing the state of isMenuOn to "true", the mapcontainer would be listening and rerender with using the new width. Although it seems like setting the width through style ={{}}, might not allow for changes?
React Leaflet will only set the width and height when the component mounts and does not update it with the state changes, in order to update the map's width you need to re-render the component fully and to do that set the component's key to something that will change with the isMenuOpen value
here is an example
<MapContainer
center={position}
zoom={zoom}
zoomControl={false}
key={isMenuOn ? "open-state": "closed-state"}
style={{
height: "100vh",
width: isMenuOn ? "80vw" : "100vw"
}}
>
The accepted answer works, but I suspect it would cause a full map reload. You can try keeping the width value static in the MapContainer element, and instead change it the wrapping div like this:
<div style={{ width: isMenuOn ? '80vw' : '100vw' }}>
<MapContainer
center={position}
zoom={zoom}
zoomControl={false}
style={{
height: '100vh',
width: '100%',
}}
/>
</div>
There is a caveat though; the map needs to be informed of the change in size, otherwise it will seem buggy. I suspect that's why the developers don't update the style after the map mount.
You can however add a map child that monitors the isMenuOn prop (or any other prop that changes your layout), and let the map instance know they should invalidate everything about sizing:
function LayoutListener({ isMenuOn }) {
const map = useMap();
useEffect(() => {
map?.invalidateSize();
}, [map, isMenuOn]);
return null;
}
And then just put in the MapContainer children:
<MapContainer>
<LayoutListener isMenuOn={isMenuOn} />
{otherChildren}
</MapContainer>

How to show only one Item at a time in React native's FlatLists?

I would really like to make this design but I don't know how to implement it in code, any suggestions?The issue is:I don't know how to show only one item at a time on the FlatList and how to make the centered item look closer.Lastly,How can I make the scroll go from one item to the other,without beeing sort of in the middle?
I tried looking online but I haven't been able to find what I need, if you found something please let me know.
I think you are looking for a carousel. Please refer to this library.
A list that allows both dragging and pressing a button.
For that i would use a horizontal FlatList. Then, make each item in the list take up 100% of the screen width and use the FlatList's ref param to scroll to the next item in the list when pressing a button and have a useState to keep track of which index the user is at to align button and swiping.
Heres how i would do it.
Get 100% screen width
import { Dimensions } from 'react-native';
const { width } = Dimensions.get('window');
Set up horizontal FlatList
The key here is the params: pagingEnabled and horizontal.
onViewableItemsChanged is called whenever focused item changes.
useCallback is for optimization. import it with useState
// Method passed to FlatList. Displays the data's text.
const renderItem = useCallback(
({ item }) => (
<View style={[styles.card, { width }]}>
<Text style={styles.cardItem}>{item.text}</Text>
</View>
),
[]
);
<FlatList
ref={flatListRef} // Reference to list. Used to scroll to specific items.
horizontal
pagingEnabled // cause snapping to items
data={data}
renderItem={renderItem}
onViewableItemsChanged={onScroll} // Calling with anonymous function here causes issues
viewabilityConfig={{
itemVisiblePercentThreshold: 100,
}}
/>
Button
Using the flatListRef and my useState, to scroll to the next index and keep track of where the user is at.
import React, { useState, useRef, useCallbac } from 'react';
const flatListRef = useRef(null);
const [currentSectionIndex, setCurrentSectionIndex] = useState(0);
const onButtonPress = useCallback(() => {
if (currentSectionIndex === data.length - 1) {
// What you want to do at the end of the list.
} else if (flatListRef.current) {
// Go to the next item
flatListRef.current.scrollToIndex({
index: currentSectionIndex + 1,
});
setCurrentSectionIndex(currentSectionIndex + 1);
}
}, [currentSectionIndex, data.length]);
OnScroll function
We wanted to allow dragging and pressing a button to go move on in the list.
So when the user scrolls, we use this function, which we passed to the FlatLists onViewableItemsChanged
// When scrolling set useState to keep track of where the user is at.
const onScroll = useCallback(({ viewableItems }) => {
if (viewableItems.length === 1) {
setCurrentSectionIndex(viewableItems[0].index);
}
}, []);

render objects in specific position with parametrize in react native

so i want to create an object, a message boxes that will be rendered on the screen in a relative position in the container.
i know to use position: 'relative' or 'absolute' and use the top and left values, but i want in addition to get the specific coordinates from the container component.
each instance of message box i want to render in a specific location retrieved from the container.
in general i cant find something in react native that fit my needs... im trying to make an app with managing objects on the screen in absolute position, all the algorithm where to render and how to move will be managed by me, but i cant find a good way to do that in react native seems like all the styles are better suit for relative and rendering obejcts by order design, someone has any tips?
enter code here:
export default class Message extends Component {
constructor(props) {
super(props)
};
render() {
var position = StyleSheet.create({top: this.props.top,
left: this.props.left});
var absoluteCircle = StyleSheet.flatten([styles.circle,
position]);
return (
<View style={absoluteCircle}>
<Text style={styles.circleText}>{this.props.bubbleText}
</Text>
</View>
);
}
}

Funky Image Positioning in react native? [duplicate]

This question already has answers here:
Image Alignment when using resizeMode = contain
(3 answers)
Closed 3 years ago.
I'm trying to create an image that fits snugly at the top of the screen of my device. Basically, a header image. At long last I've been able to scale the image to the width of the screen, but now that I have it, it always gives itself an extra top margin that I can't seem to get around. I've played around with flex properties but nothing seems to work! I was wondering if anyone had experienced an issue like this before. I'm a bit new to CSS and such so forgive me if my question is dumb.
Here is what appears (the margin is well above 25 pixels):
https://imgur.com/a/9Mzql
My code is as follows (simplified for you all):
import React, { Component } from 'react';
import {
View,
Image,
StyleSheet,
} from 'react-native';
export class Home extends Component {
static NavOption = {
title: 'Home',
};
render() {
return (
<View>
<View style={{flex: 1, justifyContent: 'flex-start'}}>
<Image
source={require('./pictures/my-image.png')}
style={styles.headerImage}
resizeMode='contain'
/>
</View>
</View>
);
}
}
const styles = StyleSheet.create({
headerImage: {
maxWidth: '100%',
},
});
resizeMode='contain' actually centers and pads the image based on how it's resized. You will have to calculate and set the height dynamically.
Here is a good example of how that can be done:
Image Alignment when using resizeMode = contain
Gordon, not a dumb question. I am having the exact same issue. I did what ReyHaynes suggested (thanks!) but in my case, modified the example he linked to for my situation:
original example
The example expects a static maxWidth/maxHeight to return a set of dimensions for your image. Since i didn't know what those vars needed to be, here's how i modified his example to work for my situation:
import { Dimensions } from 'react-native';
then, change this...
var maxWidth = 110;
var maxHeight = 30;
to...
var maxWidth = Dimensions.get('window').width;
var maxHeight = height;
Finally, follow the original example and implement as he suggested.

How can i scroll top on onPress of button in react-native?

I have added the button in bottom of simple screen and I want to scroll top whenever I press the button. what code to add to button onPress?, Please suggest any solution, Thanks in advance.
I am assuming you are using a ScrollView on your page since you want to scroll to the top whenever a button is pressed at the bottom. In that case, you can use scrollTo({x: 0, y: 0, animated: true}) method of ScrollView. You can call a function before the render method like this:
goToTop = () => {
this.scroll.scrollTo({x: 0, y: 0, animated: true});
}
render() {
return (
<ScrollView
ref={(c) => {this.scroll = c}}
>
// [rest of your code here...]
<Button title='Go To Top' onPress={this.goToTop} />
</ScrollView>
)
}
Basically, you have to create a reference(ref) to your scrollView and then you can call its method anywhere in your code.
In case you are not using ScrollView, but instead, you are using the Flatlist component, it also has a method exposed via its refs called scrollToOffset().
In React Native for functional component, need to do following things to work scroll Top in ScrollView-
1.Define globally in functional component :-
const scroll = React.createRef();
then, do add :- ref={scroll} in ScrollView.
3.Finally, on click add :-
scroll.current.scrollTo(0); // will scroll to the top at y-position 0
// const scroll = React.createRef();
if u get Error that scroll.current is Null then try this
const scroll = React.useRef();
This worked in my Case.

Resources