Closed erandagan closed 2 months ago
Hi there, as the README states yes you can use them with Skia with some extra work from the user as demostrated in the Example App while using CropZoom with Skia, anyway I've been thinking of expanding the primitives for this use case, so let me address some concers first.
These APIS are meant to recycle as much code as possible, they're 100% unsuable for a user of the library as it requires the creation of several shared values, calculate stuff like max scale yourself and many more.
Even if you wanted to pretty much rewrite any of the components yourself, setting the functions of these APIS to a Gesture is not as easy as setting it to a GestureDetector and then you're done, so they are out of the table.
Although its possible it requires much more effort than it meets the eye, not only for me but for the end user aswell in order to make them functional, I have also made use of some nonesenses ("tricks") that would need to be reimplemented by the end user, this leading to a poor dx.
All components but Gallery come with onGestureActive
callback which reports the changes on their transformation values, so it would be easier to work around that and provide a boilerplate for these use cases, kinda like this one:
import {
useDerivedValue,
useSharedValue,
type SharedValue,
} from 'react-native-reanimated';
import type { ResumableZoomState } from '../components/resumable/types';
type ResumableValues = {
onUpdate: (state: ResumableZoomState) => void;
matrix: Readonly<SharedValue<number[]>>;
};
export const useResumableValues = (): ResumableValues => {
const translateX = useSharedValue<number>(0);
const translateY = useSharedValue<number>(0);
const scale = useSharedValue<number>(1);
const matrix = useDerivedValue<number[]>(() => {
return [
scale.value,
0,
0,
0,
0,
scale.value,
0,
0,
0,
0,
1,
0,
translateX.value,
translateY.value,
0,
1,
];
}, [scale, translateX, translateY]);
const onUpdate = (state: ResumableZoomState) => {
'worklet';
translateX.value = state.translateX;
translateY.value = state.translateY;
scale.value = state.scale;
};
return { onUpdate, matrix };
};
With an expected usage like this one:
const { onUpdate, matrix } = useResumableValues();
// onGestureActive will be renamed to onUpdate in the next major release
<ResumableZoom onGestureActive={onUpdate}>
<SomeTransparentView />
</ResumableZoom>
....
// Somewhere in Skia
<Canvas>
<Group matrix={matrix}>
<Image {...props} />
</Group>
</Canvas>
Due to the small complexity of its usage I think an entry in docs as an usage guide would help for a better understanding of its usage, like "How to use with Skia Components".
Let me know your thoughts.
I've writen a new guide in docs for the intended usage of both libraries together How to use with Skia Components, this is temporary but I think it will serve well, I've decided what I commented will be the expected API to deal with this issue.
Just released version 3.0.0 including the new useTransformationState hook, I decided to use a transform based approach rather than a matrix approach because RN and RN Skia use different matrix conventions, RN uses row major syntax and Skia column major syntax, what looks fine on one will look completely distorted in the other.
Summary
Great work on this. It'd be super helpful if the library would also expose its lower level APIs (
useXCommons
) for integration in custom components (like Skia elements) which need to be made interactive.As the README states:
Expected API
import { usePanCommons, usePinchCommons } from "react-native-zoom-toolkit
Another option is to export the high-level API in the form of hooks which return transformation matrices, which can be then applied to RN views, Skia views, or further extended in other ways.