I need to find out position of item in the list view (like rectForRowAtIndexPath does for UITableView), how it is possible?
I use the built in onLayout function for a view. For instance:
<View onLayout={this.handleLayout}/>
Then your function will have:
handleLayout: function(event){
var {x, y, width, height} = event.nativeEvent.layout;
console.log('x pos:' + x + ' / y pos:' + y + ' / width:' + width + ' / height:' + height);
},
Hope this helps!
I believe that this will work:
make sure each item has unique ref prop (more about ref props in React documentation: https://facebook.github.io/react/docs/more-about-refs.html)
in your code whenever you need call "measure" method on this.refs.your_reference. Make sure it is in componentDidMount(), however there might be a need to (Warning! Hacks!) to call it via setTimeout method as described here React-Native : measure a View
Related
On web, you can get any element by its position:
document.elementFromPoint(x, y)
Is there something similar in React Native? Can it be done with a native bridge (Java/Objective C)?
I would like to get an element on screen by position X and Y (Ignoring empty places and following transformation or styling calculations like padding, margin, borderRadius) then set it a native prop or dispatch events.
OBS: I'm not referring to onLayout property or any other declared in the component's construction/render, my idea is from any X and Y position get an element that corresponds to these coordinates then get a reference to it. A use case for example: Create a virtual cursor that dispatch click events on correct components, following margin/padding and ignoring pointerEvents none.
Image Example
You can use onLayout prop of React Native components.
You should check this link
Yes you can get your current elemnts position like in. 2 ways,
onLayout
suppose on click of that element you want to know that location
assign a ref to that
const newRef = useRef();
onButtonPress = () => {
newRef?.current?.measureInWindow( (fx, fy, width, height, px, py) => {
console.log('Component width is: ' + width)
console.log('Component height is: ' + height)
console.log('X offset to frame: ' + fx)
console.log('Y offset to frame: ' + fy)
console.log('X offset to page: ' + px)
console.log('Y offset to page: ' + py)
})
}
const onLayout=(event)=> {
const {x, y, height, width} = event.nativeEvent.layout;
}
return(
<TouchableOpacity ref={useRef} onLayout={onLayout} onPress={onButtonPress} >
</TouchableOpacity>
)
There are 4 images. Whenever I swap them, I want to have a smooth animated transition. How may I apply that in my current code?
Click here to view the code
Also please check out the 2nd screenshot. I don't want the left swap option to be active when there is no image. But it swaps 1 extra time and stops. What is wrong with my logic?
Here is the screenshot
Have a try with the below code:
const handleSwipeLeft = () => {
if (activeImg < totalImage - 1) {
setActiveImage(currActive => currActive + 1)
}
}
as the length greater than the index.
I need to get a list of components (x, y) at specified coordinates, preferably in order from children to grandparents. Would be awesome if absolutely positioned components were taken into account.
Think: which components (and in what order) would have the opportunity to react to a click/touch event at (x, y).
I am currently trying to build a mechanism that would keep track of every component that exists, and what are it's relations to other components (which one is parent, which one is children, so I can sort them). It's ugly, lots of edgecases, components that I wish were trackable need to know about it and cooperate, and I think I'm just reimplementing something that's already there.
EDIT: This is (probably) not about measuring. It's about asking "what components are currently rendered under pixel (123,456)"
measure is react native default method for any component to get update on it.
Below is the example which help you to get x and y coordinate:
class screenname extends React.Component {
render() {
return <View ref={view => { this.screenname = view; }} />
}
componentDidMount() {
// Print component dimensions to console
this.screenname.measure( (fx, fy, width, height, px, py) => {
console.log('Component width is: ' + width)
console.log('Component height is: ' + height)
console.log('X : ' + fx)
console.log('Y : ' + fy)
console.log('X offset to page: ' + px)
console.log('Y offset to page: ' + py)
})
}
}
To find position of children with respect to parent what you have to do is pass parent reference to measureLayout function like below:-
import {findNodeHandle} from 'react-native';
calculateDimensions(){
const handler = findNodeHandle(this.rootRef);
this.childRef.measureLayout(handler, ( X_Position, Y_Position, Width, Height ) =>
{
this.setState({
X_Dimension : X_Position,
Y_Dimension: Y_Position,
Child_View_Height: Height,
Child_View_Width: Width
});
});
}
//Parent with nested child
<View ref={(ref) => this.rootRef = ref}>
<View ref={(ref) => this.childRef = ref}>
</View>
</View>
Hope this will help
I'm trying to render an curved vertical list like this iOS component: https://github.com/makotokw/CocoaWZYCircularTableView
That component (written in Obj-c) iterates the visible cells when laying them out, and sets the frame (i.e. indent) using asin.
I know in React Native I can set the leftMargin style in the renderItem callback, but I can't figure out how to get the on-screen index of the item - all I have is the index into the source data. And also, at that point, I don't think I have access to the absolute position.
Any ideas?
The function you are looking for is
onViewableItemsChanged.
You can use it with viewabilityConfig which provides us with
minimumViewTime,viewAreaCoveragePercentThreshold,waitForInteraction
which can be set accordingly
const VIEWABILITY_CONFIG = {
minimumViewTime: 3000,
viewAreaCoveragePercentThreshold: 100,
waitForInteraction: true,
};
_onViewableItemsChanged = (info: {
changed: Array<{
key: string,
isViewable: boolean,
item: any,
index: ?number,
section?: any,
}>
}
){
//here you can have the index which is visible to you
}
<FlatList
renderItem={this.renderItem}
data={this.state.data}
onViewableItemsChanged={this._onViewableItemsChanged}
viewabilityConfig={VIEWABILITY_CONFIG}
/>
Thanks for both answers.
What I have ended up doing is deriving the visible items using the scroll offset of the list. This is simple because the list items all have the same height.
I do this in the onScroll handler, and at that point I calculate the horizontal offset for each item (and I use leftMargin / rightMargin to render this). It's not perfect, but it does give me an elliptical list.
_handleScroll = (event) => {
const topItemIndex = Math.floor(event.nativeEvent.contentOffset.y / LIST_ITEM_HEIGHT);
const topItemSpare = LIST_ITEM_HEIGHT-(event.nativeEvent.contentOffset.y % LIST_ITEM_HEIGHT);
const positionFromEllipseTop = (forIndex-topItemIndex)*LIST_ITEM_HEIGHT+topItemSpare;
const positionFromOrigin = Math.floor(Math.abs(yRadius - positionFromEllipseTop));
const angle = Math.asin(positionFromOrigin / yRadius);
if (orientation === 'Left') {
marginLeft = 0;
marginRight = ((xRadius * Math.cos(angle)))-LIST_ITEM_HEIGHT;
alignSelf = 'flex-end';
}
else if (orientation === 'Right') {
marginLeft = (xRadius * Math.cos(angle))-LIST_ITEM_HEIGHT;
marginRight = 0;
alignSelf = 'flex-start';
}
}
React-native's FlatList component has a prop called onLayout. You can get the position of the component on screen with this prop.
onLayout
Invoked on mount and layout changes with:
{nativeEvent: { layout: {x, y, width, height}}}
This event is fired immediately once the layout has been calculated,
but the new layout may not yet be reflected on the screen at the time
the event is received, especially if a layout animation is in
progress.
Basically this is used to creat a horizontal parallax effect. I use anchor links to move the page back and forth ebtween pages horizontally, which all works nicely.
Now i want to include the parallax background, which also works on the first try. below is my javascript:
<script>
$(document).ready(function () {
$("#nav a").bind("click", function (event) {
$("section").removeClass('current');
$("#nav a").removeClass('current');
event.preventDefault();
var target = $(this).attr("href");
$("#wrapper").stop().animate({
scrollLeft: $(target).position().left - $("#container").position().left,
scrollTop: $(target).position().top - $("#container").position().top,
},
1000);
var x = $("#wrapper").scrollLeft();
$("#parallax").animate({
'background-position-x': '+20%',
'background-position-y': '0%'
}, 1200);
$(target).addClass('current');
$(this).addClass('current');
});
});
</script>
what this colde does is add a class to my nav links and the section which is on screen, then animates to that section on screen, after which the parallax div should move too. This works on the first click to a new section, but after that it just stays.
I think the fault lies in the
-position-x': '+20%',
line of code, but I do not know why this wouldn't work. Has anyone got any thoughts?
I am not sure that you can use += in the way you are trying to.
If I understand what you are trying to do I think your logic is slightly wrong. When you click you want to move the background by 20% right? In order to do that make moving the background a function which you can call when you want to move it by 20px. Something like:
var moveBackground = function(){
// First get the current background position - assuming its 0 on first time around
var currentX = parseInt($("#parallax).css('background-position-x'));
var newX = currentX + 20;
$("#parallax").animate({
'background-position': newX + '%' + ' 0%'
}, 1200);
$(target).addClass('current');
$(this).addClass('current');
});
}
This is completely untested code, I wrote whilst at work so don't hate me if that doesnt work.