How can I detect if the touch is over the border of a View from PanResponder? - react-native

I'm working on a Image cropper, I have somehow figure out how to move the cropper even it's not a perfect solution but it works, but now I want to respond to the border touches/moves of a given View
I'm using this module for the corpping, but actually I'm still stuck at how to respond to border touches/moves

gestureState parameter is sufficient for the task.
x0 and y0 are the top-left coordinates of the responder view, further, moveX and moveY holds the current coordinates of touch.
So moveX === x0 means current touch is at left edge.
Similarly moveY === y0 means current touch is at top edge.
For handling right and bottom edge I suggest you use onLayout in the <View> tag and assign height and width of the view to some variable or in state variable( take care of performances optimisations)
And then use it in similar way:
onPanresponderMove(evt, {x0, y0, moveX, moveY) {
...
if(moveX=== x0 || moveX === x0 + this.state._currentWidth) {
// task for left and right edge response
...
}
...
}
To get view width:
<View {...this._myResponder.panHandlers}
onLayout={ ({width, height}) => this.state._currentWidth = width } />

Related

React Native - Scrollview - Apply a zoom using a method/function not pinch

As the zoomScale parameter does not seem to affect the initial zoom level, I would like to set a zoom on my ScrollView using a method/function.
I found that via the ScrollView reference, I can get the responder and then apply scrollResponderZoomTo but it's iOS only.
Is there a way to manipulate the zoom of a ScrollView by another way than the pinch gesture?
Answering my own question, it's possible to use the function scrollResponderZoomTo on the responder of the ScrollView via the reference of the component :
...
<ScrollView
ref={this.scrollViewRef}
...
And a call like this :
this.scrollViewRef.current?.getScrollResponder().scrollResponderZoomTo({
x: viewContentOffsetX || 0,
y: viewContentOffsetY || 0,
width: widthOfTheVisiblePart,
height: heightOfTheVisiblePart,
animated: false})
Up to a function to calculate the visible part based on the expected zoom value

Rotate View/Image around specific point, not center (React Native)

I'm trying to rotate a view around a certain point not the center (just like transform-origin in css) in React Native. At this time elements can only be rotated around the center. The result should be two views/images containing a point laying upon each other at exactly this point, while one of the views is rotated at the desired point. React Native does not support this layout feature yet, so I have to calculate the offsets and then add them using translateX and translateY.
I've tried several approaches e.g. this but I'm not getting the desired result. Reacts matrix transform is deprecated, so better not use it. I know that it has to be simple trigonometry stuff but I don't have any idea.
I think at first I need to diff the position of the point from the center of the object, then apply a angle, and then? If I use the offset calculated before applying the rotation, i don't get the rotation at the desired point.
Thanks for answers!
here is an image of the problem
I just made a withAnchorPoint function to make transform working with anchor point easier in react-native. https://github.com/sueLan/react-native-anchor-point.
You can use it like this:
import { withAnchorPoint } from 'react-native-anchor-point';
getTransform = () => {
let transform = {
transform: [{ perspective: 400 }, { rotateX: rotateValue }],
};
return withAnchorPoint(transform, { x: 0.5, y: 0 }, { width: CARD_WIDTH, height: CARD_HEIGHT });
};
<Animated.View style={[styles.blockBlue, this.getTransform()]} />
I also wrote an article for it.
So I finally found a way and formular to calculate the offset. The desired point of rotation gets obviously rotated as well, when applying an angle to the object. So what I had to do was getting the position of this point (lets call it pRotated) by using rotationmatrices with the position of both the center (m) of the object and the desired point of rotation (p) like this:
angle = alpha * (Math.PI / 180)
pRotated.x = m.x + (p.x - m.x) * Math.cos(angle) - (p.y - m.y) * Math.sin(angle)
pRotated.y = m.y + (p.x - m.x) * Math.sin(angle) + (p.y - m.y) * Math.cos(angle)
Then it was easy to get the offset using
translateX = pRotated.x - p.x
translateY = pRotated.y - p.y
which then can just be applied to the object, and then its rotated by alpha around point p.
I've attached a scribble for further explanation.

Hold Position of ScrollView when adding data

I am trying to make it so whenever something new is rendered into a scroll view, the scroll view will stay put and not bump up and down. Right now if a new component is rendered in, the scrollview appears to be reset to 0.
Is there a way to stop this behavior, and hold position?
Right now for the scrollview I am using:
handleScrollt(event){
this.scroll = event.nativeEvent.contentOffset.y
}
handleSizet(width, height){
if (this.scroll) {
const position = this.scroll + height - this.height
this.refs.sv.scrollTo({x: 0, y: position, animated: false})
}
this.height = height
}
<ScrollView
ref="sv"
scrollEventThrottle={16}
onScroll={this.handleScrollt.bind(this)}
onContentSizeChange={this.handleSizet.bind(this)}
The issue with this is the scrollview will render briefly, before then scrolling to the correct offset. So it seems like theres a brief splash of the top of the screen
you have to define a height for the scrollview.
If the scrollview is supposed to cover an entire View you can get the view's height by:
<View style={styles.contactView} onLayout={(event) => {
var contactViewY = event.nativeEvent.layout.y;
this.setState({contactViewY: contactViewY})
}}>
and then give it to the scrollview
<ScrollView style={[styles.contactScroller, {height: this.state.contactViewY}]}>
Bear in mind that the onLayout method is called immediately once the layout has been calculated, so if the view's height changes later, this two lines of code alone won't update it.
You should try maintainVisibleContentPosition.
Example:
<ScrollView
{...props}
maintainVisibleContentPosition={{
minIndexForVisible: 0,
}}
/>
From the docs:
maintainVisibleContentPosition
When set, the scroll view will adjust the scroll position so that the
first child that is currently visible and at or beyond
minIndexForVisible will not change position. This is useful for lists
that are loading content in both directions, e.g. a chat thread, where
new messages coming in might otherwise cause the scroll position to
jump. A value of 0 is common, but other values such as 1 can be used
to skip loading spinners or other content that should not maintain
position.

How do I make Scrollview auto scroll when the content size changes in React Native

I currently have a vertical ScrollView that has many expandable cards inside. When one of the cards expands, its height will increase by Y, and therefore the ScrollView content size's height will increase by Y.
I want to make the ScrollView automatically scroll by Y when the content size increases, and scroll by -Y when the content size decreases. How should I achieve this?
You can use "onContentSizeChange", this will return new height after change your view. It's work for me.
<ScrollView
ref={scrollView => {
this.scrollView = scrollView;
}}
onContentSizeChange={(contentWidth, contentHeight) => {
console.log('contentHeight :==> \n', contentHeight);
this.scrollView.scrollTo({
x: 0,
y: contentHeight + YOUR_VIEW_HEIGHT - SCREEN_HEIGTH,
animated: true,
});
}}
>
...
YOUR_VIEW_HEIGHT will get from View's onLayout method.

Titanium/ Alloy: Reapply styles on when screen is resized

I have some basic styles like:
"#foo": {
backgroundColor: '#ff0000', // red
}
"#foo[if=Alloy.Globals.isSmallHeight]": {
backgroundColor: '#0000ff', // blue
}
in alloy.js I have the following:
function pxToDp(px){
return px / (Titanium.Platform.displayCaps.dpi / 160);
}
var screenWidth;
var screenHeight;
if (Ti.Platform.name == "android") {
screenWidth = pxToDp(Ti.Platform.displayCaps.platformWidth);
screenHeight = pxToDp(Ti.Platform.displayCaps.platformHeight);
} else {
screenWidth = Ti.Platform.displayCaps.platformWidth;
screenHidth = Ti.Platform.displayCaps.platformHeight;
}
Alloy.Globals.isSmallHeight= screenHeight <= 545;
This basically means the background colour of #foo is blue if the screen height is less than or equal to 545dp, and red otherwise.
This usually works fine. However, there are times when the height of the screen can change during run-time. For example:
Screen Orientation Change
Multi window (on Android)
Adjusting the splitter position while in multi window mode (Android)
The issue with this is that the styles are not re-applied to take into account the new screen width and screen height.
For example, let's say there is a screen of size 600dp x 300dp in the portrait position. #foo will correctly have a background colour of red.
However, if the orientation changes, the screen size is now: 300dp x 600dp, but the #foo does not re-check the height a background colour, and thus is still red instead of blue.
A similar issue occurs when going into split screen.
Therefore my question is, how can I reapply styles when the screen dimensions changes?
Have a look at the dynamic styles section in the documentation
http://docs.appcelerator.com/platform/latest/#!/guide/Dynamic_Styling
http://docs.appcelerator.com/platform/latest/#!/guide/Dynamic_Styles
it will give you a basic idea on how to create style at runtime and apply them. You could do this inside the orientation change event