react-native-magic-move
Version:
Create magical move transitions between scenes in react-native
129 lines (114 loc) • 3.74 kB
JavaScript
/* eslint react/prop-types: 0 */
function resolveValue(value, def) {
if (value !== undefined) return value;
return def || 0;
}
export default function dottedTransition({ from, to, render, interpolate }) {
const colCount = 4;
const rowCount = 4;
function convertToTiles(isTarget) {
function interpolate2(start, end, clamped) {
return interpolate(
isTarget ? end : start,
isTarget ? start : end,
clamped
);
}
const result = [];
const clone = isTarget ? to : from;
const { width, height, style, start, end } = clone;
const {
borderRadius,
borderTopLeftRadius,
borderTopRightRadius,
borderBottomLeftRadius,
borderBottomRightRadius
} = style;
for (let rowIndex = 0; rowIndex < rowCount; rowIndex++) {
for (let colIndex = 0; colIndex < colCount; colIndex++) {
const tileIndex = result.length;
// Update size to be the size of a tile
style.width = width / colCount;
style.height = height / rowCount;
// Specify content style to show only a portion
// of the content
clone.contentStyle = {
position: "absolute",
width: width,
height: height,
left: colIndex * -style.width,
top: rowIndex * -style.height
};
// Clip the contents
style.overflow = "hidden";
// Position the tile
style.transform = [
{ translateX: (isTarget ? end.x : start.x) + style.width * colIndex },
{
translateY: (isTarget ? end.y : start.y) + style.height * rowIndex
},
{ scaleX: interpolate2(1, 0) },
{ scaleY: interpolate2(1, 0) }
];
// Calculate border-radius for this tile
style.borderRadius = 0;
style.borderTopLeftRadius = 0;
style.borderTopRightRadius = 0;
style.borderBottomLeftRadius = 0;
style.borderBottomRightRadius = 0;
if (rowIndex === 0 && colIndex === 0) {
style.borderTopLeftRadius = resolveValue(
borderTopLeftRadius,
borderRadius
);
} else if (rowIndex === 0 && colIndex === colCount - 1) {
style.borderTopRightRadius = resolveValue(
borderTopRightRadius,
borderRadius
);
} else if (rowIndex === rowCount - 1 && colIndex === 0) {
style.borderBottomLeftRadius = resolveValue(
borderBottomLeftRadius,
borderRadius
);
} else if (rowIndex === rowCount - 1 && colIndex === colCount - 1) {
style.borderBottomRightRadius = resolveValue(
borderBottomRightRadius,
borderRadius
);
}
// Animate border radius into a circle
const endBorderRadius = Math.max(style.width / 2, style.height / 2);
style.borderTopLeftRadius = interpolate2(
style.borderTopLeftRadius,
endBorderRadius
);
style.borderTopRightRadius = interpolate2(
style.borderTopRightRadius,
endBorderRadius
);
style.borderBottomLeftRadius = interpolate2(
style.borderBottomLeftRadius,
endBorderRadius
);
style.borderBottomRightRadius = interpolate2(
style.borderBottomRightRadius,
endBorderRadius
);
// Render
result.push(render(clone, tileIndex));
}
}
return result;
}
const fromTiles = convertToTiles(false);
const toTiles = convertToTiles(true);
//
// Render
//
return [...fromTiles, ...toTiles];
}
dottedTransition.defaultProps = {
useNativeDriver: true,
nativeContentType: "snapshot"
};