在 Manus 中运行任何 Skill
一键导入
一键导入
一键在 Manus 中运行任何 Skill
开始使用manga-reader
星标7
分支1
更新时间2026年1月15日 19:02
Reader screen patterns and image handling
安装
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
SKILL.md
readonly菜单
Reader screen patterns and image handling
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
| name | Manga Reader |
| description | Reader screen patterns and image handling |
| Mode | Description | Implementation |
|---|---|---|
| Vertical | Scroll through pages | FlatList vertical |
| Horizontal | Swipe left/right | FlatList horizontal paging |
| Webtoon | Long strip format | FlatList with variable height |
function ReaderScreen() {
const { manga, chapter, sourceId } = useRoute().params;
const [pages, setPages] = useState<string[]>([]);
const [currentPage, setCurrentPage] = useState(0);
const [readerMode, setReaderMode] = useState('vertical');
useEffect(() => {
loadPages();
}, [chapter]);
const loadPages = async () => {
const urls = await sourceService.getChapterPages(sourceId, chapter.id);
setPages(urls);
};
return (
<View style={styles.container}>
{readerMode === 'vertical' ? (
<VerticalReader pages={pages} onPageChange={setCurrentPage} />
) : (
<HorizontalReader pages={pages} onPageChange={setCurrentPage} />
)}
<ReaderOverlay
currentPage={currentPage}
totalPages={pages.length}
chapter={chapter}
/>
</View>
);
}
<FlatList
data={pages}
keyExtractor={(_, index) => `page-${index}`}
renderItem={({ item: url, index }) => (
<Image
source={{ uri: url }}
style={styles.page}
contentFit="contain"
cachePolicy="memory-disk"
/>
)}
onViewableItemsChanged={handleViewableChange}
viewabilityConfig={{ itemVisiblePercentThreshold: 50 }}
/>
<FlatList
data={pages}
horizontal
pagingEnabled
showsHorizontalScrollIndicator={false}
keyExtractor={(_, index) => `page-${index}`}
renderItem={({ item: url }) => (
<View style={styles.pageContainer}>
<Image source={{ uri: url }} style={styles.fullPage} />
</View>
)}
getItemLayout={(_, index) => ({
length: screenWidth,
offset: screenWidth * index,
index,
})}
onMomentumScrollEnd={handleScrollEnd}
/>
const { updateProgress } = useLibrary();
// Save progress on page change
useEffect(() => {
updateProgress(manga.id, chapter.id, currentPage);
}, [currentPage]);
// Restore progress on load
useEffect(() => {
const savedPage = readingProgress[manga.id]?.page || 0;
flatListRef.current?.scrollToIndex({ index: savedPage });
}, []);
import * as ScreenOrientation from 'expo-screen-orientation';
// Lock on enter
useEffect(() => {
ScreenOrientation.unlockAsync(); // Allow all orientations
return () => {
ScreenOrientation.lockAsync(ScreenOrientation.OrientationLock.PORTRAIT);
};
}, []);
// Tap zones for navigation
const handleTap = (x: number) => {
const width = Dimensions.get('window').width;
if (x < width * 0.3) {
goToPreviousPage();
} else if (x > width * 0.7) {
goToNextPage();
} else {
toggleOverlay();
}
};
// Go to next chapter
const goToNextChapter = () => {
const currentIndex = chapters.findIndex(c => c.id === chapter.id);
if (currentIndex > 0) {
navigation.replace('Reader', {
manga,
chapter: chapters[currentIndex - 1],
sourceId,
});
}
};
import { Image } from 'expo-image';
// Prefetch next pages
useEffect(() => {
const nextPages = pages.slice(currentPage + 1, currentPage + 4);
nextPages.forEach(url => Image.prefetch(url));
}, [currentPage]);
import * as NavigationBar from 'expo-navigation-bar';
import { StatusBar } from 'expo-status-bar';
// Hide UI
<StatusBar hidden={isFullScreen} />
await NavigationBar.setVisibilityAsync('hidden');
Image caching and storage management with expo-image
Reusable component patterns and styling
URL schemes and deep link handling
Background chapter downloads and offline reading
Common patterns for Expo SDK 54 and React Native development
Paperback-compatible extension runtime and source API