Limiting containers to three fixed sizes - javascript

I'm looking at the react-grid-layout which is based on Material Design's 12 column grid. Is there a way to provide pre-defined sizes for containers to stick to the following 3 sizes: 1 full width (12 cols), half grid (6 cols) or 1/3 grid (4 cols)?
Sandbox

My guess is that when you say container, you're referring to the layout items. If that is the case, use a custom onResize method. Using the sandbox code you have from your question:
export default class ShowcaseLayout extends React.Component {
constructor(props) {
...
// add the line below
this.onResize = this.onResize.bind(this);
}
...
// add the method
onResize(layout, oldLayoutItem, layoutItem, placeholder) {
// `oldLayoutItem` contains the state of the item before the resize.
// You can modify `layoutItem` to enforce constraints.
const allowableW = this.props.cols[this.state.currentBreakpoint] - oldLayoutItem.x
if (layoutItem.w <= 4) {
layoutItem.w = 4;
placeholder.w = 4;
} else if (layoutItem.w <= 6) {
layoutItem.w = allowableW < 6 ? 4 : 6;
placeholder.w = allowableW < 6 ? 4 : 6;
} else {
layoutItem.w = allowableW < 12 ? 6 : 12;
placeholder.w = allowableW < 12 ? 6 : 12;
}
}
render() {
return (
<div>
...
<ResponsiveReactGridLayout
...
{/* bind method to component */}
onResize={this.onResize}
>
{this.generateDOM()}
</ResponsiveReactGridLayout>
</div>
);
}
}
ShowcaseLayout.propTypes = {
onLayoutChange: PropTypes.func.isRequired
};
ShowcaseLayout.defaultProps = {
...
// ensure your breakpoints have a minimum of 4 columns
cols: { lg: 12, md: 10, sm: 6, xs: 4, xxs: 4 },
};
function generateLayout() {
return _.map(_.range(0, 25), function (item, i) {
var y = Math.ceil(Math.random() * 4) + 1;
return {
x: (_.random(0, 5) * 2) % 12,
y: Math.floor(i / 6) * y,
// set item's default width to 4
w: 4,
h: y,
i: i.toString(),
static: Math.random() < 0.05
};
});
}
DEMO

I don't know much about react-grid-layout.
But you can do it by a simple change in the cols property of ShowcaseLayout.defaultProps like following.
ShowcaseLayout.defaultProps = {
className: "layout",
rowHeight: 30,
onLayoutChange: function() {},
cols: { lg: 12, md: 12, sm: 6, xs: 4, xxs: 4 },
initialLayout: generateLayout()
};
UPDATED Sandbox

Yes, you can certainly do that with react-grid-layout. In the section of their documentation labeled "Usage without Browserify/Webpack", they have this code snippet:
import { Responsive as ResponsiveGridLayout } from 'react-grid-layout';
class MyResponsiveGrid extends React.Component {
render() {
// {lg: layout1, md: layout2, ...}
const layouts = getLayoutsFromSomewhere();
return (
<ResponsiveGridLayout className="layout" layouts={layouts}
breakpoints={{lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0}}
cols={{lg: 12, md: 10, sm: 6, xs: 4, xxs: 2}}>
<div key="1">1</div>
<div key="2">2</div>
<div key="3">3</div>
</ResponsiveGridLayout>
)
}
}
You can modify the breakpoints however you like, which indicate at which screen/viewport width's the screen will consider a new size (e.g. lg vs. md vs. sm, etc.).
Once you've defined your breakpoints, define how many columns you would like each container to be at different breakpoints using the cols attribute. If you only want the three sizes you mentioned—1 full width (12 cols), ½ grid (6 cols), and ⅓ grid (4 cols)—adjust the cols attribute to something like this:
cols={{lg: 12, md: 6, sm: 6, xs: 4, xxs: 4}}
Using these redefined values, elements in this grid will be full-width on lg viewports, ½ the grid on md and sm viewports, and ⅓ the grid on xs and xxs viewports.

Related

FIlter array of rectangles so that there are no collisions

I have an array of rectangles that might collide with each other. I want to filter out the collided ones with minimal reduction. What's an optimal way of doing this?
Here is some code for context:
type Rect = {
x: number;
y: number;
width: number;
height: number;
};
function isRectsColliding(rect1: Rect, rect2: Rect) {
return !(
rect1.x > rect2.x + rect2.width ||
rect1.x + rect1.width < rect2.x ||
rect1.y > rect2.y + rect2.height ||
rect1.y + rect1.height < rect2.y
);
}
const rects = [
{ x: 0, y: 181, width: 6, height: 6 },
{ x: 6, y: 147, width: 6, height: 6 },
{ x: 32, y: 124, width: 6, height: 6 },
{ x: 34, y: 7, width: 6, height: 6 },
{ x: 35, y: 11, width: 6, height: 6 },
{ x: 36, y: 0, width: 6, height: 6 },
{ x: 39, y: 15, width: 6, height: 6 },
];
const filteredRectIndexes = rects.reduce(?).map((_, idx) => idx); // should be [0, 1, 2, 3, 5, 6]
Thanks.
Here is an example of a reduce function that you can use to get the result that you've mentioned:
function isRectsColliding(rect1, rect2) {
return !(
rect1.x > rect2.x + rect2.width ||
rect1.x + rect1.width < rect2.x ||
rect1.y > rect2.y + rect2.height ||
rect1.y + rect1.height < rect2.y
);
}
const rects = [{
x: 0,
y: 181,
width: 6,
height: 6
},
{
x: 6,
y: 147,
width: 6,
height: 6
},
{
x: 32,
y: 124,
width: 6,
height: 6
},
{
x: 34,
y: 7,
width: 6,
height: 6
},
{
x: 35,
y: 11,
width: 6,
height: 6
},
{
x: 36,
y: 0,
width: 6,
height: 6
},
{
x: 39,
y: 15,
width: 6,
height: 6
},
];
const filteredRectIndexes = rects.reduce((a, c) => {
if (a.length && a.some((r) => isRectsColliding(r, c))) {
return a;
}
return [...a, c];
}, [])
.map((r) => rects.indexOf(r)); // should be [0, 1, 2, 3, 5, 6]
console.log(filteredRectIndexes);
I've modified the callback passes to .map(..) because .map((_, idx) => idx) will always return an empty array or an array of consecutive numbers.
Like #derpirscher mentioned, this will not give you the biggest set of non-colliding rectangles because it processes rectangles in the order that they are in the original array (current rectangle does not collide with any of the previous rectangles).
Keeping the maximum number of non-colliding rectangles can get quite complex, a simple way of doing it will be to first sort the original array of rectangles by the number of collisions each of them has, here is an example:
function isRectsColliding(rect1, rect2) {
return !(
rect1.x > rect2.x + rect2.width ||
rect1.x + rect1.width < rect2.x ||
rect1.y > rect2.y + rect2.height ||
rect1.y + rect1.height < rect2.y
);
}
const rects = [{
x: 0,
y: 181,
width: 6,
height: 6
},
{
x: 6,
y: 147,
width: 6,
height: 6
},
{
x: 32,
y: 124,
width: 6,
height: 6
},
{
x: 34,
y: 7,
width: 6,
height: 6
},
{
x: 35,
y: 11,
width: 6,
height: 6
},
{
x: 36,
y: 0,
width: 6,
height: 6
},
{
x: 39,
y: 15,
width: 6,
height: 6
},
];
const rectsWithCount = rects.map((c, _, arr) => {
const count = arr.filter((r) => r !== c && isRectsColliding(r, c)).length;
return { ...c, count };
});
rectsWithCount.sort((a, b) => a.count - b.count);
const filteredRectIndexes = rectsWithCount.reduce((a, c) => {
if (a.length && a.some((r) => isRectsColliding(r, c))) {
return a;
}
return [...a, c];
}, [])
.map((r) => rects.findIndex((rect) => r.x === rect.x && r.y === rect.y && r.width === rect.width && r.height === rect.height));
console.log(filteredRectIndexes);
Based on your declaration that the rectangles are squares of the same width, after scaling this width to 1, this problem is maximum independent set in the intersection graph of unit squares. Unfortunately, Dániel Marx ("Parameterized Complexity of Independence and Domination on Geometric Graphs", 2006) showed that it's W[1]-hard, which means that we don't have a guaranteed fast and high-quality approximation, let alone an exact algorithm.
Practically speaking, if I absolutely needed the optimal solution, I would compute the graph (bucket squares by (floor(x / width), floor(y / width)), check each 2x2 bucket block for overlaps) and hand off the resulting maximum independent set problem to a mixed integer program (MIP) solver. For a user interface, however, this seems like a bad idea, since the MIP solver will take an unpredictable and possibly large amount of time to find an optimal solution.
Instead, I would focus on maximal independent sets. A maximal independent set may not include as many squares as the maximum independent set, but you can't add a square without creating an overlap, so IMO it should look OK. Titus's answer will give you a maximal independent set.
For scalability and consistent zooming, I would also suggest that you compute consistent maximal independent sets for all possible zooms offline. The zoom needed for two squares to overlap is a monotone function of the Manhattan (L1) distance between their centers. If you can afford quadratic time for preprocessing, select the two furthest squares first, then repeatedly select the next square with the maximum minimum distance to a square already selected. Show a prefix of this list depending on the zoom. You can figure out where the prefix ends by doing binary search (record the minimum distances during preprocessing). If quadratic is too much, there are faster but more complicated algorithms to the same end; see farthest-first traversal.

Javascript Canvas clearRec() makes everything white, doesn't draw tiles set map, only draws the last layer

I am building my own Javascript game with canvas. I've set up the game loop with everything working. The only problem was smudging character, which I solved by adding clearRect() at the beginning of each frame draw. Now the problem I am facing is that it only draws the character clearly, without any smudging but the map tile set is white, basically it doesn't draw the map or probably doesn't have enough time to draw. Tried to use game loop as setInterval((){}, 16.7), same issue. What could be the problem? Hope you can help.
MAIN WORLD FILE:
import WorldMap from './WorldMap'
export default class World {
constructor(config) {
this.element = config.element
this.canvas = this.element.querySelector('#game__canvas')
this.ctx = this.canvas.getContext('2d')
this.map = null
}
startGameLoop() {
const step = () => {
this.ctx.clearRect(0,0, this.canvas.width, this.canvas.height)
// Draws lower layer
this.map.drawLowerImage(this.ctx)
// Draws game objects
Object.values(this.map.gameObjects).forEach(object => {
object.x += 0.02
object.sprite.draw(this.ctx)
})
// THIS IS THE GAME LOOP
requestAnimationFrame(() => {
step()
})
}
step()
}
init() {
this.map = new WorldMap(window.WorldMaps.DemoRoom)
this.startGameLoop()
// CANVAS SIZING TO GET CRISP IMAGES
// AFTER TESTING THIS IS WHAT CAUSING THE PROBLEM, BUT IF I DELETE THIS getBoundingClientRect() the images in canvas become too big and blurry.
const canvasWrapperRect = document.getElementById('game__container').getBoundingClientRect();
this.canvas.width = canvasWrapperRect.width;
this.canvas.height = canvasWrapperRect.height;
// CANVAS RESIZE ON SCREEN SIZE CHANGE
window.onresize = () => {
location.reload()
}
this.ctx.scale(1.2, 1.2)
}
}
MAP STRUCTURE LOGIC (I draw the map based on tiles, not as a single big image, using the atlas image) (Source example and suggestions can be found here: https://developer.mozilla.org/en-US/docs/Games/Techniques/Tilemaps/Square_tilemaps_implementation:_Static_maps)
import GameObject from './GameObject'
export default class WorldMap {
constructor(config) {
this.gameObjects = config.gameObjects
// LOWER LEVEL TILES
this.lowerImage = new Image()
this.lowerImage.src = config.lowerSrc
this.mapTileSettings = config.mapTileSettings
// UPPER LEVEL TILES ON TOP OF PLAYERS
this.upperImage = new Image()
this.upperImage.src = config.upperSrc
}
drawLowerImage(ctx) {
this.lowerImage.onload = () => {
for (let c = 0; c < this.mapTileSettings.cols; c++) {
for (let r = 0; r < this.mapTileSettings.rows; r++) {
const tile = this.mapTileSettings.getTile(c, r)
if (tile !== 0) {
ctx.imageSmoothingEnabled = false;
ctx.drawImage(
this.lowerImage,
(tile - 1) * 64,
0,
this.mapTileSettings.tsize,
this.mapTileSettings.tsize,
c * this.mapTileSettings.tsize,
r * this.mapTileSettings.tsize,
this.mapTileSettings.tsize,
this.mapTileSettings.tsize,
)
}
}
}
}
}
// drawUpperImage(ctx) {
// ctx.drawImage(this.upperImage, 0, 0)
// }
}
window.WorldMaps = {
DemoRoom: {
lowerSrc: require('../../assets/tiles.png'),
// upperSrc: require('../../assets/tiles.png'),
mapTileSettings: { //mapImage
cols:8,
rows:8,
tsize:64,
tiles: [
1, 3, 3, 3, 1, 1, 3, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 2, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 2, 1, 1, 1, 1,
1, 1, 1, 1, 2, 1, 1, 1,
1, 1, 1, 1, 2, 1, 1, 1,
1, 1, 1, 0, 0, 1, 1, 1
],
getTile(col, row) {
return this.tiles[row * this.cols + col]
}
},
gameObjects: {
hero: new GameObject({
src: require('../../assets/hero.png'),
x: 5,
y: 6,
})
}
},
}
NOTE: I am using require() because the Webpack complains about not being able to find source images.

React native stylesheet multiple values in css statement

I think this question is best described by an example:
let's say I want to apply margin to an element like this:
const myView = () => <View style={styles.viewStyle}></View>
const styles = StyleSheet.create({
viewStyle: {
margin: "0 0 5 10",
},
})
Is it possible to do this without multiple margin statements?
Thanks for reading.
I don't think you can unless you write a function to do something like that.
Like this:
const CommonStyle = {
margin: (t, r, b, l) => {
marginTop: t,
marginRight: r,
marginBottom: b,
marginLeft: l,
}
}
Then in your style:
const styles = StyleSheet.create({
viewStyle: {
...CommonStyle.margin(0, 0, 5, 10),
},
})
But, in the most common case, we atmost only change margin for 2 directions. And there are serveral options to quickly styling your component when you get used to styling.
Example:
"5 10 5 10" is equal to
{
marginVertical: 5,
marginHorizontal: 10,
}
"0 0 0 5" is equal to
{
margin: 0,
marginLeft: 5,
}

React Spring - useTrail delay issues

Currently been using react-spring to do our animations in our app; unfortunately, animation is not something I excel in and the design our designer gave us for our new logo is leaving me stumped on implementation. It is pretty easy with plain old JS but implementing it in react-spring has proved a challenge that I can not get past.
The end goal for the animation is to look like this:
https://codepen.io/darylginn/pen/GRqZxBZ
Currently, I am up to this stage:
import React from "react";
import { useTrail, animated } from "react-spring";
const Loader: React.FC = () => {
// Animations
const paths = [
{
id: 1,
color: "#466FB5",
d: "M90.6672 33H16L53.3336 96.4409L90.6672 33Z",
},
{
id: 2,
color: "#0093D3",
d: "M53.3347 96.4443H128.002L90.6683 33.0034L53.3347 96.4443Z",
},
{
id: 3,
color: "#53BFA2",
d: "M128.001 96.3701H53.3336L90.6672 159.811L128.001 96.3701Z",
},
{
id: 4,
color: "#93C83F",
d: "M90.6675 159.892H165.335L128.001 96.4417L90.6675 159.892Z",
},
{
id: 5,
color: "#58B647",
d: "M165.334 159.892H90.6664L128 223.333L165.334 159.892Z",
},
{
id: 6,
color: "#F2E90B",
d: "M202.667 96.4436H128L165.334 159.894L202.667 96.4436Z",
},
{
id: 7,
color: "#FBB12C",
d: "M128.001 96.4443H202.668L165.335 33.0034L128.001 96.4443Z",
},
{
id: 8,
color: "#FF5E8D",
d: "M240 33H165.333L202.666 96.4409L240 33Z",
},
];
const trail = useTrail(paths.length, {
from: {
scale: 1,
},
to: async (next: any) => {
while (1) {
await next({ scale: 1.5 });
await next({ scale: 1 });
}
},
});
return (
<div style={{ width: "200px", height: "200px" }}>
<svg
width="72"
height="72"
viewBox="0 0 256 256"
fill="none"
xmlns="http://www.w3.org/2000/svg"
style={{ overflow: "visible" }}>
{trail.map(({ scale }, index) => {
const path = paths[index];
return (
<animated.path
key={path.id}
fill={path.color}
d={path.d}
style={{
transformOrigin: "center",
transform: scale.interpolate((s: any) => `scale(${s})`),
}}
/>
);
})}
</svg>
</div>
);
};
The main issue I am at now is the scale of each triangle in the SVG needs to happen one after another, but nothing I do with the useTrail make this happen.
I did try adding a delay like this to the useTrail
delay: (key: any) => key * 200
But the delay doesn't even seem to make a difference. If someone could help make sure each triangle finish it sequences before the next one starts that would be great.
Bonus if you can also help me add the colour change as seen in the original design (see link).
I have tried posting in the react-spring community but got no replies
I would change the useTrail to one useSpring for all the triangles. If you change the x value from 0 to 8, then you can use interpolate and a range for each triangle to change. For example for the second triangle you can use range:[0,1,1.5,2,8],output:[1,1,1.5,1,1]. It means that when x is between 1 and 2 it will change the scale from 1 to 1.5 to 1 and all other places it will remain 1.
const props = useSpring({
from: {
x: 0
},
config: {
duration: 4000
},
to: async (next: any) => {
while (1) {
await next({ x: 8 });
await next({ reset: true });
}
}
});
I also added the color interpolation.
{paths.map((path, index) => {
const colors = [];
for (let i = 0; i < 8; i++) {
colors.push(paths[(i + index) % 8].color);
}
return (
<animated.path
key={path.id}
fill={path.color}
d={path.d}
style={{
transformOrigin: "center",
transform: props.x
.interpolate({
range: [0, index, index + 0.5, index + 1, 8],
output: [1, 1, 1.5, 1, 1]
})
.interpolate((x) => `scale(${x})`),
fill: props.x.interpolate({
range: [0, 1, 2, 3, 4, 5, 6, 7, 8],
output: colors
})
}}
/>
);
})}
I have an example. There is some glitch with the center triangle. But I think you get the idea.
Example: https://codesandbox.io/s/animate-triangles-sequentially-with-interpolating-and-range-oer84

Panresponder or Animated.View doesnt work when the item to animate is in front of a scrollable view

Hey everyone :) Should be a function for a navigation avatar which sticks to the closest corner. While coding I used a simple circle as a placeholder. The problem is that the following code works perfectly fine when imported to another screen, but when I replace <View style={styles.circle} /> with an image <Image source={require("../assets/dude.png")} resizeMode="contain" style={{width: 180, height: 240,}}/> it doesnt work anymore? Like I can see the image, but the animations work extremely buggy and it just goes anywhere, nothing like it's supposed to do?
I tried it also with Animated.Image instead of the view and giving it all the parameters, still no change. The weird thing is that the Image works perfectly fine if I were to run this code as a screen itself, but when I import it only the circle view works, not the image?
EDIT: Just found the issue: if the Animated.Image is in front of a Scrollable View, even if it isn't part of that View, it bugs. If I replace the image with anything else (like a Box), it works fine, only the image bugs in that manner :) which leads me to my next question: How can I fix that?
so this is my code:
import React from "react";
import {
StyleSheet,
View,
Dimensions,
Animated,
PanResponder,
Image,
} from "react-native";
export default class Avatar extends React.Component {
constructor(props) {
super(props);
this.state = {
pan: new Animated.ValueXY(),
screenMeasurements: {
width: Screen.width / 2,
height: Screen.height / 2,
},
};
this.panResponder = PanResponder.create({
onStartShouldSetPanResponder: () => true,
onPanResponderGrant: () => {
this.state.pan.setOffset({
x: this.state.pan.x._value,
y: this.state.pan.y._value,
});
},
onPanResponderMove: Animated.event([
null,
{
dx: this.state.pan.x,
dy: this.state.pan.y,
},
]),
onPanResponderRelease: (e, gesture) => {
if (this.whichField(gesture) == 1) {
console.log("top left");
this.state.pan.flattenOffset();
Animated.spring(this.state.pan, {
toValue: {
x: (Screen.width * 0.5 - 90) * -1,
y: (Screen.height * 0.5 - 120) * -1,
},
}).start();
} else if (this.whichField(gesture) == 2) {
console.log("top right");
this.state.pan.flattenOffset();
Animated.spring(this.state.pan, {
toValue: {
x: Screen.width * 0.5 - 90,
y: (Screen.height * 0.5 - 120) * -1,
},
}).start();
} else if (this.whichField(gesture) == 3) {
console.log("bottom left");
this.state.pan.flattenOffset();
Animated.spring(this.state.pan, {
toValue: {
x: (Screen.width * 0.5 - 90) * -1,
y: Screen.height * 0.5 - 150,
},
}).start();
} else {
console.log("bottom right");
this.state.pan.flattenOffset();
Animated.spring(this.state.pan, {
toValue: {
x: Screen.width * 0.5 - 90,
y: Screen.height * 0.5 - 150,
},
}).start();
}
},
});
}
whichField(gesture) {
var sm = this.state.screenMeasurements;
let field;
{
gesture.moveY < sm.height && gesture.moveX < sm.width
? (field = 1)
: gesture.moveY < sm.height && gesture.moveX > sm.width
? (field = 2)
: gesture.moveY > sm.height && gesture.moveX < sm.width
? (field = 3)
: (field = 4);
}
return field;
}
render() {
return (
<View style={styles.draggableContainer}>
<Animated.View
style={[this.state.pan.getLayout()]}
{...this.panResponder.panHandlers}
>
<View style={styles.circle} />
</Animated.View>
</View>
);
}
}
let Screen = Dimensions.get("screen");
let CIRCLE_RADIUS = 45;
const styles = StyleSheet.create({
text: {
marginTop: 25,
marginLeft: 5,
marginRight: 5,
textAlign: "center",
color: "#fff",
},
draggableContainer: {
position: "absolute",
top: Screen.height / 2 - CIRCLE_RADIUS,
left: Screen.width / 2 - CIRCLE_RADIUS,
},
circle: {
backgroundColor: "#1abc9c",
width: CIRCLE_RADIUS * 2,
height: CIRCLE_RADIUS * 2,
borderRadius: CIRCLE_RADIUS,
},
});
Check out this similar animation of badge Above ScrollView.
You need to place the Image inside an Animated View.
Example code:
import React, {Component} from 'react';
import {
StyleSheet,
View,
PanResponder,
Animated,
Dimensions,
ScrollView,
Image,
} from 'react-native';
const {height, width} = Dimensions.get('screen');
export default class SampleApp extends Component {
constructor() {
super();
this._animatedValue = new Animated.ValueXY({x: 20, y: 20});
this._value = {x: 20, y: 20};
this._animatedValue.addListener((value) => (this._value = value));
this._panResponder = PanResponder.create({
onMoveShouldSetResponderCapture: () => true,
onMoveShouldSetPanResponderCapture: () => true,
onPanResponderGrant: (e, gestureState) => {
this._animatedValue.setOffset({x: this._value.x, y: this._value.y});
this._animatedValue.setValue({x: 0, y: 0});
},
onPanResponderMove: Animated.event([
null,
{dx: this._animatedValue.x, dy: this._animatedValue.y},
]),
onPanResponderRelease: (e, gesture) => {
this._animatedValue.flattenOffset();
if (this.whichField(gesture) == 1) {
Animated.spring(this._animatedValue, {
toValue: {x: 20, y: 20},
}).start();
} else if (this.whichField(gesture) == 2) {
Animated.spring(this._animatedValue, {
toValue: {x: width - 120, y: 20},
}).start();
} else if (this.whichField(gesture) == 3) {
Animated.spring(this._animatedValue, {
toValue: {x: 20, y: height - 150},
}).start();
} else {
Animated.spring(this._animatedValue, {
toValue: {x: width - 120, y: height - 150},
}).start();
}
},
});
}
whichField(gesture) {
var sm = {height, width};
let field;
{
gesture.moveY < sm.height / 2 && gesture.moveX < sm.width / 2
? (field = 1)
: gesture.moveY < sm.height / 2 && gesture.moveX > sm.width / 2
? (field = 2)
: gesture.moveY > sm.height / 2 && gesture.moveX < sm.width / 2
? (field = 3)
: (field = 4);
}
return field;
}
render() {
return (
<View style={styles.container}>
<ScrollView>
{['', '', '', '', '', ''].map(() => (
<View style={styles.scrollItem} />
))}
</ScrollView>
<Animated.View
style={[
styles.box,
{
transform: [
{translateX: this._animatedValue.x},
{translateY: this._animatedValue.y},
],
},
]}
{...this._panResponder.panHandlers}>
<Image
source={{
uri:
'https://pluspng.com/img-png/user-png-icon-male-user-icon-512.png',
}}
style={StyleSheet.absoluteFill}
/>
</Animated.View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
box: {
width: 100,
height: 100,
borderRadius: 50,
backgroundColor: '#fff',
position: 'absolute',
},
scrollItem: {
height: 300,
width: '100%',
backgroundColor: 'grey',
marginBottom: 10,
},
});
Check in Expo
I hope it will help you.

Categories

Resources