Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
142 changes: 142 additions & 0 deletions example/src/reproducers/Issue393DisplayZoom.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
import { useEffect, useState } from 'react';
import {
View,
Text,
StyleSheet,
Pressable,
type ViewStyle,
} from 'react-native';
import {
RiveView,
Fit,
useRiveFile,
type RiveFile,
} from '@rive-app/react-native';
import { type Metadata } from '../shared/metadata';

/**
* Issue #393: on iOS devices where UIScreen.nativeScale != scale (Display
* Zoom, iPhone mini and Plus), MTKView sizes its drawable through ancestor
* transforms. A rotated parent squashes the artboard; a parent at scale(0)
* when the view mounts leaves it blank after the scale returns to 1.
*
* Run on an iPhone 13 mini simulator. All three artboards should keep the
* same aspect ratio, including after Remount and Resize.
*/

const W = 100;
const H = 148;
const ZERO_SCALE_HOLD_MS = 1500;

function Cell({
label,
transform,
file,
resized,
}: {
label: string;
transform: ViewStyle['transform'];
file: RiveFile;
resized: boolean;
}) {
const size = resized ? styles.resized : styles.size;
return (
<View style={styles.cell}>
<Text style={styles.cellLabel}>{label}</Text>
<View style={[styles.frame, size, { transform }]}>
<RiveView file={file} fit={Fit.Contain} style={size} />
</View>
</View>
);
}

export default function Issue393DisplayZoom() {
const { riveFile, error } = useRiveFile(
require('../../assets/rive/rewards.riv')
);
const [generation, setGeneration] = useState(0);
const [zeroScaled, setZeroScaled] = useState(true);
const [resized, setResized] = useState(false);

useEffect(() => {
setZeroScaled(true);
const timer = setTimeout(() => setZeroScaled(false), ZERO_SCALE_HOLD_MS);
return () => clearTimeout(timer);
}, [generation, riveFile]);

return (
<View style={styles.container}>
<Text style={styles.subtitle}>
generation {generation} ·{' '}
{zeroScaled ? 'scale(0) holding' : 'scale(0) released'}
</Text>
{error ? <Text style={styles.error}>{String(error)}</Text> : null}
{riveFile ? (
<View style={styles.row} key={generation}>
<Cell
label="control"
transform={[]}
file={riveFile}
resized={resized}
/>
<Cell
label="rotate 14°"
transform={[{ rotate: '14deg' }]}
file={riveFile}
resized={resized}
/>
<Cell
label="scale 0→1"
transform={[{ scale: zeroScaled ? 0 : 1 }]}
file={riveFile}
resized={resized}
/>
</View>
) : (
<Text style={styles.subtitle}>loading…</Text>
)}
<Pressable
style={styles.button}
onPress={() => setGeneration((g) => g + 1)}
>
<Text style={styles.buttonText}>Remount</Text>
</Pressable>
<Pressable style={styles.button} onPress={() => setResized((r) => !r)}>
<Text style={styles.buttonText}>
{resized ? 'Restore size' : 'Resize'}
</Text>
</Pressable>
</View>
);
}

Issue393DisplayZoom.metadata = {
name: 'Issue #393: Display Zoom drawable',
description:
'iOS RiveView squashed or blank under a rotated or zero-scaled parent',
} satisfies Metadata;

const styles = StyleSheet.create({
container: { flex: 1, backgroundColor: '#fff', padding: 12 },
subtitle: { fontSize: 12, color: '#666', textAlign: 'center', margin: 8 },
error: { color: 'red', textAlign: 'center' },
row: {
flexDirection: 'row',
justifyContent: 'space-around',
marginTop: 24,
},
cell: { alignItems: 'center' },
cellLabel: { fontSize: 12, marginBottom: 16 },
frame: { backgroundColor: '#dde6ff' },
size: { width: W, height: H },
resized: { width: W * 1.3, height: H * 0.7 },
button: {
marginTop: 40,
alignSelf: 'center',
backgroundColor: '#007AFF',
paddingHorizontal: 24,
paddingVertical: 12,
borderRadius: 8,
},
buttonText: { color: '#fff', fontWeight: '600' },
});
2 changes: 1 addition & 1 deletion ios/new/RiveRuntimeLogger.swift
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ final class RiveRuntimeLogger: RiveRuntime.RiveLog.Logger, @unchecked Sendable {
// first frame(s) have no drawable yet; the SDK logs that transient
// condition at error level, which LogBox turns into a red screen in dev.
// Rendering recovers on the next tick, so forward it as debug instead.
// https://github.com/rive-app/rive-ios/blob/6.26.0/Source/Concurrency/View/RiveUIView.swift#L451-L456
// https://github.com/rive-app/rive-ios/blob/6.28.0/Source/Concurrency/View/RiveUIView.swift#L501-L506
if case .view = tag, text == "Draw failed: missing drawable" {
RiveLog.d(name, "\(text)\(suffix)")
return
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@
},
"homepage": "https://github.com/rive-app/rive-nitro-react-native#readme",
"runtimeVersions": {
"ios": "6.26.0",
"ios": "6.28.0",
"android": "11.12.1"
},
"publishConfig": {
Expand Down
3 changes: 1 addition & 2 deletions release-please-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@
"packages": {
".": {
"changelog-path": "CHANGELOG.md",
"include-component-in-tag": false,
"release-as": "0.5.0"
"include-component-in-tag": false
}
}
}
Loading