This commit is contained in:
oneao committed 2026-04-11 17:09:25 +08:00
1 parent cd191fdc60
commit 4fe17847d0
18 files changed
+474 -130

No files matched your search

+1 -1
View File
@@ -14,7 +14,7 @@ export default function RootLayout() {
return (
<ThemeProvider value={isDark ? DarkTheme : DefaultTheme}>
<StatusBar style={isDark ? "light" : "dark"} />
{/* <StatusBar style={isDark ? "light" : "dark"} /> */}
<Stack screenOptions={{ headerShown: false }} />
</ThemeProvider>
+102 -128
View File
@@ -1,144 +1,118 @@
import { BlurTargetView, BlurView } from "expo-blur";
import React, { useRef } from "react";
import { ScrollView, StyleSheet, Text, View } from "react-native";
export default function OnlyBlurDemo() {
const targetRef = useRef(null);
import Layout from "@/components/layout";
import { View, Text } from "react-native";
export default function Index() {
return (
<View style={{ flex: 1 }}>
{/* 👇 Blur 目标区域 */}
<BlurTargetView ref={targetRef} style={{ flex: 1 }}>
<ScrollView
contentContainerStyle={{ padding: 16, paddingBottom: 120 }}
removeClippedSubviews={false}
scrollEventThrottle={16}
showsVerticalScrollIndicator={false}
>
<View style={[styles.card, { backgroundColor: "#4EA0FF" }]}>
<Text style={styles.cardText}>蓝色卡片</Text>
</View>
<View style={[styles.card, { backgroundColor: "#FF9500" }]}>
<Text style={styles.cardText}>橙色卡片</Text>
</View>
<View style={[styles.card, { backgroundColor: "#34C759" }]}>
<Text style={styles.cardText}>绿色卡片</Text>
</View>
{Array.from({ length: 10 }).map((_, i) => (
<View
key={i}
style={[
styles.listItem,
{
backgroundColor: i % 2 === 0 ? "#FFFFFF" : "#F2F2F7",
},
]}
>
<Text style={styles.listText}>列表项 {i + 1}</Text>
</View>
))}
<View style={[styles.card, { backgroundColor: "#AF52DE" }]}>
<Text style={styles.cardText}>紫色区域</Text>
</View>
<View style={[styles.card, { backgroundColor: "#FF2D55" }]}>
<Text style={styles.cardText}>红色区域</Text>
</View>
</ScrollView>
</BlurTargetView>
{/* 👇 毛玻璃底部栏(稳定版) */}
<BlurView
intensity={60}
tint="light"
blurMethod="dimezisBlurView"
blurTarget={targetRef}
style={styles.blur}
>
{/* 用 overlay 替代 opacity(避免闪烁) */}
<View style={styles.overlay} />
<View style={styles.tabContent}>
<Text style={styles.tabText}>TabBar</Text>
</View>
</BlurView>
</View>
<Layout>
<View>
<Text>123</Text>
</View>
</Layout>
);
}
const styles = StyleSheet.create({
blur: {
position: "absolute",
left: 0,
right: 0,
bottom: 0,
height: 56,
overflow: "hidden",
borderRadius: 999,
margin: 16,
// import React, { useState } from "react";
// import { View, Text, StyleSheet, TouchableOpacity } from "react-native";
// import { Ionicons } from "@expo/vector-icons";
// ✨ 关键:只保留极轻“环境感”
shadowColor: "#000",
shadowOffset: { width: 0, height: 10 },
shadowOpacity: 0.03,
shadowRadius: 20,
// const TABS = [
// { label: "首页", icon: "home-outline", activeIcon: "home" },
// { label: "统计", icon: "stats-chart-outline", activeIcon: "stats-chart" },
// { label: "应用", icon: "grid-outline", activeIcon: "grid" }, // 中间
// { label: "聊天", icon: "chatbubble-ellipses-outline", activeIcon: "chatbubble-ellipses" },
// { label: "我的", icon: "person-outline", activeIcon: "person" },
// ];
// Android 基本关闭
elevation: 0,
// export default function CapsuleTabBarIconDemo() {
// const [active, setActive] = useState(0);
// ✨ 玻璃底(很关键)
backgroundColor: "rgba(255,255,255,0.10)",
// return (
// <View style={styles.container}>
// <View style={{ flex: 1 }} />
// ✨ 极弱边缘,不要存在感
borderWidth: 0.5,
borderColor: "rgba(255,255,255,0.12)",
},
// {/* 👇 悬浮 TabBar */}
// <View style={styles.wrapper}>
// <View style={styles.tabBar}>
// {TABS.map((item, index) => {
// const isActive = index === active;
overlay: {
...StyleSheet.absoluteFillObject,
backgroundColor: "rgba(249,249,249,0.4)",
},
// return (
// <TouchableOpacity
// key={index}
// style={styles.tabItem}
// onPress={() => setActive(index)}
// activeOpacity={0.8}
// >
// <Ionicons
// name={isActive ? item.activeIcon : item.icon}
// size={20}
// color={isActive ? "#111" : "#888"}
// />
tabContent: {
flex: 1,
alignItems: "center",
justifyContent: "center",
},
// <Text style={[styles.text, isActive && styles.activeText]}>{item.label}</Text>
// </TouchableOpacity>
// );
// })}
// </View>
// </View>
// </View>
// );
// }
tabText: {
fontSize: 14,
fontWeight: "600",
color: "#333",
},
// const styles = StyleSheet.create({
// container: {
// flex: 1,
// backgroundColor: "#F2F3F5",
// },
card: {
height: 120,
borderRadius: 16,
marginBottom: 16,
padding: 16,
justifyContent: "flex-end",
},
// wrapper: {
// position: "absolute",
// left: 0,
// right: 0,
// bottom: 24,
// alignItems: "center",
// },
cardText: {
color: "#FFFFFF",
fontSize: 18,
fontWeight: "600",
},
// tabBar: {
// flexDirection: "row",
// height: 64,
// paddingHorizontal: 8,
// borderRadius: 999,
listItem: {
height: 60,
borderRadius: 12,
marginBottom: 12,
paddingHorizontal: 16,
justifyContent: "center",
},
// // ✅ 半透明更高级
// backgroundColor: "rgba(255,255,255,0.95)",
listText: {
fontSize: 16,
color: "#333",
},
});
// // ✅ 极弱阴影(可去掉)
// shadowColor: "#000",
// shadowOffset: { width: 0, height: 4 },
// shadowOpacity: 0.05,
// shadowRadius: 12,
// },
// tabItem: {
// flex: 1,
// alignItems: "center",
// justifyContent: "center",
// },
// text: {
// fontSize: 11,
// marginTop: 2,
// color: "#888",
// },
// activeText: {
// color: "#111",
// fontWeight: "600",
// },
// // ⭐ 精髓:比背景高亮更高级
// indicator: {
// position: "absolute",
// bottom: 6,
// width: 16,
// height: 3,
// borderRadius: 2,
// backgroundColor: "#111",
// },
// });
@@ -0,0 +1,72 @@
import { useSafeAreaInsets } from "react-native-safe-area-context";
import React, { ReactNode } from "react";
import { View, Text } from "react-native";
import Ionicons from "@expo/vector-icons/Ionicons";
import AntDesign from "@expo/vector-icons/AntDesign";
import { ChevronLeft, SwatchBook, CircleChevronLeft, CirclePower } from "lucide-react-native";
type LayoutProps = {
children: ReactNode;
};
export default function Layout({ children }: LayoutProps) {
const insets = useSafeAreaInsets();
return (
<View className="flex-1 bg-white">
<View
style={{
flex: 1,
paddingTop: insets.top + 44,
paddingBottom: insets.bottom + 56,
}}
>
{children}
</View>
<View
className="absolute top-0 left-0 right-0"
style={{
paddingTop: insets.top,
height: insets.top + 48,
}}
>
<View className="h-12 flex-row items-center px-3">
{/* 左区域 */}
<View className="h-12 w-12 rounded-full bg-white items-center justify-center shadow-md">
<ChevronLeft size={28} />
</View>
{/* 中间标题 */}
<View className="flex-1 items-center ">
<Text className="text-xl font-semibold text-black">记账</Text>
</View>
{/* 右区域 */}
<View className="w-28 ">
<View className="h-12 flex-row items-center rounded-full bg-white shadow-md overflow-hidden">
<View className="px-4 items-center justify-center">
<SwatchBook size={22} />
</View>
<View className="w-[1px] h-4 bg-black/10" />
<View className="px-4 items-center justify-center">
<CirclePower size={22} />
</View>
</View>
</View>
</View>
</View>
<View
style={{
position: "absolute",
left: 0,
right: 0,
bottom: 0,
paddingBottom: insets.bottom,
}}
>
<Text>footer</Text>
</View>
</View>
);
}
@@ -0,0 +1,19 @@
import React from 'react';
import { View, ViewProps } from 'react-native';
import type { VariantProps } from '@gluestack-ui/utils/nativewind-utils';
import { boxStyle } from './styles';
type IBoxProps = ViewProps &
VariantProps<typeof boxStyle> & { className?: string };
const Box = React.forwardRef<React.ComponentRef<typeof View>, IBoxProps>(
function Box({ className, ...props }, ref) {
return (
<View ref={ref} {...props} className={boxStyle({ class: className })} />
);
}
);
Box.displayName = 'Box';
export { Box };
@@ -0,0 +1,19 @@
import React from 'react';
import { boxStyle } from './styles';
import type { VariantProps } from '@gluestack-ui/utils/nativewind-utils';
type IBoxProps = React.ComponentPropsWithoutRef<'div'> &
VariantProps<typeof boxStyle> & { className?: string };
const Box = React.forwardRef<HTMLDivElement, IBoxProps>(function Box(
{ className, ...props },
ref
) {
return (
<div ref={ref} className={boxStyle({ class: className })} {...props} />
);
});
Box.displayName = 'Box';
export { Box };
@@ -0,0 +1,10 @@
import { tva } from '@gluestack-ui/utils/nativewind-utils';
import { isWeb } from '@gluestack-ui/utils/nativewind-utils';
const baseStyle = isWeb
? 'flex flex-col relative z-0 box-border border-0 list-none min-w-0 min-h-0 bg-transparent items-stretch m-0 p-0 text-decoration-none'
: '';
export const boxStyle = tva({
base: baseStyle,
});
@@ -0,0 +1,22 @@
import { View, ViewProps } from 'react-native';
import React from 'react';
import { centerStyle } from './styles';
import type { VariantProps } from '@gluestack-ui/utils/nativewind-utils';
type ICenterProps = ViewProps & VariantProps<typeof centerStyle>;
const Center = React.forwardRef<React.ComponentRef<typeof View>, ICenterProps>(
function Center({ className, ...props }, ref) {
return (
<View
className={centerStyle({ class: className })}
{...props}
ref={ref}
/>
);
}
);
Center.displayName = 'Center';
export { Center };
@@ -0,0 +1,20 @@
import React from 'react';
import { centerStyle } from './styles';
import type { VariantProps } from '@gluestack-ui/utils/nativewind-utils';
type ICenterProps = React.ComponentPropsWithoutRef<'div'> &
VariantProps<typeof centerStyle>;
const Center = React.forwardRef<HTMLDivElement, ICenterProps>(function Center(
{ className, ...props },
ref
) {
return (
<div className={centerStyle({ class: className })} {...props} ref={ref} />
);
});
Center.displayName = 'Center';
export { Center };
@@ -0,0 +1,8 @@
import { tva } from '@gluestack-ui/utils/nativewind-utils';
import { isWeb } from '@gluestack-ui/utils/nativewind-utils';
const baseStyle = isWeb ? 'flex flex-col relative z-0' : '';
export const centerStyle = tva({
base: `justify-center items-center ${baseStyle}`,
});
@@ -0,0 +1,27 @@
import React from 'react';
import type { VariantProps } from '@gluestack-ui/utils/nativewind-utils';
import { View } from 'react-native';
import type { ViewProps } from 'react-native';
import { hstackStyle } from './styles';
type IHStackProps = ViewProps & VariantProps<typeof hstackStyle>;
const HStack = React.forwardRef<React.ComponentRef<typeof View>, IHStackProps>(
function HStack({ className, space, reversed, ...props }, ref) {
return (
<View
className={hstackStyle({
space,
reversed: reversed as boolean,
class: className,
})}
{...props}
ref={ref}
/>
);
}
);
HStack.displayName = 'HStack';
export { HStack };
@@ -0,0 +1,26 @@
import React from 'react';
import type { VariantProps } from '@gluestack-ui/utils/nativewind-utils';
import { hstackStyle } from './styles';
type IHStackProps = React.ComponentPropsWithoutRef<'div'> &
VariantProps<typeof hstackStyle>;
const HStack = React.forwardRef<React.ComponentRef<'div'>, IHStackProps>(
function HStack({ className, space, reversed, ...props }, ref) {
return (
<div
className={hstackStyle({
space,
reversed: reversed as boolean,
class: className,
})}
{...props}
ref={ref}
/>
);
}
);
HStack.displayName = 'HStack';
export { HStack };
@@ -0,0 +1,25 @@
import { isWeb } from '@gluestack-ui/utils/nativewind-utils';
import { tva } from '@gluestack-ui/utils/nativewind-utils';
const baseStyle = isWeb
? 'flex relative z-0 box-border border-0 list-none min-w-0 min-h-0 bg-transparent items-stretch m-0 p-0 text-decoration-none'
: '';
export const hstackStyle = tva({
base: `flex-row ${baseStyle}`,
variants: {
space: {
'xs': 'gap-1',
'sm': 'gap-2',
'md': 'gap-3',
'lg': 'gap-4',
'xl': 'gap-5',
'2xl': 'gap-6',
'3xl': 'gap-7',
'4xl': 'gap-8',
},
reversed: {
true: 'flex-row-reverse',
},
},
});
@@ -0,0 +1,28 @@
import React from 'react';
import type { VariantProps } from '@gluestack-ui/utils/nativewind-utils';
import { View } from 'react-native';
import { vstackStyle } from './styles';
type IVStackProps = React.ComponentProps<typeof View> &
VariantProps<typeof vstackStyle>;
const VStack = React.forwardRef<React.ComponentRef<typeof View>, IVStackProps>(
function VStack({ className, space, reversed, ...props }, ref) {
return (
<View
className={vstackStyle({
space,
reversed: reversed as boolean,
class: className,
})}
{...props}
ref={ref}
/>
);
}
);
VStack.displayName = 'VStack';
export { VStack };
@@ -0,0 +1,27 @@
import React from 'react';
import type { VariantProps } from '@gluestack-ui/utils/nativewind-utils';
import { vstackStyle } from './styles';
type IVStackProps = React.ComponentProps<'div'> &
VariantProps<typeof vstackStyle>;
const VStack = React.forwardRef<React.ComponentRef<'div'>, IVStackProps>(
function VStack({ className, space, reversed, ...props }, ref) {
return (
<div
className={vstackStyle({
space,
reversed: reversed as boolean,
class: className,
})}
{...props}
ref={ref}
/>
);
}
);
VStack.displayName = 'VStack';
export { VStack };
@@ -0,0 +1,25 @@
import { isWeb } from '@gluestack-ui/utils/nativewind-utils';
import { tva } from '@gluestack-ui/utils/nativewind-utils';
const baseStyle = isWeb
? 'flex flex-col relative z-0 box-border border-0 list-none min-w-0 min-h-0 bg-transparent items-stretch m-0 p-0 text-decoration-none'
: '';
export const vstackStyle = tva({
base: `flex-col ${baseStyle}`,
variants: {
space: {
'xs': 'gap-1',
'sm': 'gap-2',
'md': 'gap-3',
'lg': 'gap-4',
'xl': 'gap-5',
'2xl': 'gap-6',
'3xl': 'gap-7',
'4xl': 'gap-8',
},
reversed: {
true: 'flex-col-reverse',
},
},
});