u'
This commit is contained in:
1 parent
cd191fdc60
commit
4fe17847d0
18 files changed
+474
-130
No files matched your search
@@ -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
@@ -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',
|
||||
},
|
||||
},
|
||||
});
|
||||
Reference in new issue
Block a user