空间功能初步搭建
This commit is contained in:
parent
6316142a70
commit
3508f92c63
42
App.jsx
42
App.jsx
|
@ -37,6 +37,8 @@ import Search from "./screeens/Search";
|
|||
import CreatePost from "./screeens/CreatePost";
|
||||
import WebWithHeader from "./screeens/WebWithHeader";
|
||||
import WebWithoutHeader from "./screeens/WebWithoutHeader";
|
||||
import SpaceIntroduce from "./screeens/SpaceIntroduce";
|
||||
import StreamerSpace from "./screeens/StreamerSpace";
|
||||
import UpdateModal from "./components/UpdateModal";
|
||||
import StreamerNavigatorModal from "./components/StreamerNavigatorModal";
|
||||
import { Icon } from "@rneui/themed";
|
||||
|
@ -571,6 +573,46 @@ export default function App() {
|
|||
title: "",
|
||||
})}
|
||||
/>
|
||||
<RootStack.Screen
|
||||
name="SpaceIntroduce"
|
||||
component={SpaceIntroduce}
|
||||
options={({ navigation }) => ({
|
||||
headerLeft: () => (
|
||||
<TouchableOpacity onPress={() => navigation.goBack()}>
|
||||
<NativeImage
|
||||
source={require("./assets/icon/others/goback.png")}
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
),
|
||||
headerRight: () => (
|
||||
<NativeImage
|
||||
source={require("./assets/icon/others/setting.png")}
|
||||
/>
|
||||
),
|
||||
headerTransparent: true,
|
||||
title: "",
|
||||
})}
|
||||
/>
|
||||
<RootStack.Screen
|
||||
name="StreamerSpace"
|
||||
component={StreamerSpace}
|
||||
options={({ navigation }) => ({
|
||||
headerLeft: () => (
|
||||
<TouchableOpacity onPress={() => navigation.goBack()}>
|
||||
<NativeImage
|
||||
source={require("./assets/icon/others/goback.png")}
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
),
|
||||
headerRight: () => (
|
||||
<NativeImage
|
||||
source={require("./assets/icon/others/setting.png")}
|
||||
/>
|
||||
),
|
||||
headerTransparent: true,
|
||||
title: "",
|
||||
})}
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
|
|
|
@ -20,6 +20,8 @@ export default function Empty({ type }) {
|
|||
return require("../../assets/images/icon_emptyinternet.png");
|
||||
case "nodata":
|
||||
return require("../../assets/images/icon_emptydata.png");
|
||||
case "nospace":
|
||||
return require("../../assets/icon/others/nodata.png");
|
||||
}
|
||||
};
|
||||
const text = (type) => {
|
||||
|
@ -38,12 +40,16 @@ export default function Empty({ type }) {
|
|||
return "网络好像出错了,试着下拉刷新一下吧!";
|
||||
case "nodata":
|
||||
return "这里空空如也哦~";
|
||||
case "nospace":
|
||||
return "暂时没有加入的空间哦";
|
||||
}
|
||||
};
|
||||
return (
|
||||
<View style={tailwind("flex flex-1 justify-center items-center mt-32")}>
|
||||
<Image style={tailwind("w-28 h-28")} source={source(type)} />
|
||||
<Text style={tailwind("text-sm text-[#FFFFFF80]")}>{text(type)}</Text>
|
||||
<Text style={tailwind("text-sm text-[#FFFFFF40] mt-3")}>
|
||||
{text(type)}
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
import {
|
||||
View,
|
||||
Text,
|
||||
TouchableOpacity,
|
||||
Image as NativeImage,
|
||||
} from "react-native";
|
||||
import React from "react";
|
||||
import { useTailwind } from "tailwind-rn";
|
||||
import { Image } from "expo-image";
|
||||
import { useNavigation } from "@react-navigation/native";
|
||||
|
||||
const placeholder = "https://via.placeholder.com/1024x1024.png";
|
||||
|
||||
export default function SpaceCard({ data }) {
|
||||
const navigation = useNavigation();
|
||||
const tailwind = useTailwind();
|
||||
const blurhash = "LcKUTa%gOYWBYRt6xuoJo~s8V@fk";
|
||||
|
||||
return (
|
||||
<TouchableOpacity
|
||||
activeOpacity={1}
|
||||
onPress={() => navigation.navigate("StreamerSpace")}
|
||||
style={tailwind("w-full px-1 mt-2")}
|
||||
>
|
||||
<View style={tailwind("flex flex-col rounded-lg overflow-hidden")}>
|
||||
<Image
|
||||
source={placeholder}
|
||||
contentFit="cover"
|
||||
transition={1000}
|
||||
placeholder={blurhash}
|
||||
cachePolicy="disk"
|
||||
style={{ aspectRatio: "1/1", ...tailwind("w-full z-0") }}
|
||||
/>
|
||||
<NativeImage
|
||||
style={{ right: 2, ...tailwind("absolute top-0") }}
|
||||
source={require("../../assets/icon/others/space_new.png")}
|
||||
/>
|
||||
<View
|
||||
style={{
|
||||
height: 42,
|
||||
...tailwind(
|
||||
"flex flex-row w-full items-center px-2.5 bg-[#FFFFFF1A]"
|
||||
),
|
||||
}}
|
||||
>
|
||||
<Text
|
||||
style={tailwind("shrink text-white text-sm font-medium")}
|
||||
numberOfLines={1}
|
||||
ellipsizeMode="tail"
|
||||
>
|
||||
哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈
|
||||
</Text>
|
||||
<NativeImage
|
||||
style={tailwind("ml-1")}
|
||||
source={require("../../assets/icon/others/pay_space.png")}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
}
|
|
@ -58,11 +58,13 @@
|
|||
"react-native": "0.72.6",
|
||||
"react-native-gifted-chat": "^2.4.0",
|
||||
"react-native-image-zoom-viewer": "^3.0.1",
|
||||
"react-native-pager-view": "6.2.0",
|
||||
"react-native-picker-select": "^8.1.0",
|
||||
"react-native-safe-area-context": "4.6.3",
|
||||
"react-native-screens": "~3.22.0",
|
||||
"react-native-svg": "13.9.0",
|
||||
"react-native-swiper": "^1.6.0",
|
||||
"react-native-tab-view": "^3.5.2",
|
||||
"react-native-toast-message": "^2.1.6",
|
||||
"react-native-web": "~0.19.6",
|
||||
"react-native-webview": "13.2.2",
|
||||
|
|
|
@ -5,6 +5,7 @@ import { useTailwind } from "tailwind-rn";
|
|||
import Stream from "../Stream";
|
||||
import My from "../My";
|
||||
import Posts from "../Posts";
|
||||
import Space from "../Space";
|
||||
import { get } from "../../utils/storeInfo";
|
||||
import { Icon } from "@rneui/themed";
|
||||
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
||||
|
@ -73,6 +74,7 @@ export default function HomeTab({ navigation, route }) {
|
|||
)}
|
||||
>
|
||||
<TouchableOpacity
|
||||
onPress={() => navigation.navigate("SpaceIntroduce")}
|
||||
style={tailwind("flex flex-col items-center basis-1/3")}
|
||||
>
|
||||
<Icon type="ionicon" name="image" size={30} color="white" />
|
||||
|
@ -133,6 +135,8 @@ export default function HomeTab({ navigation, route }) {
|
|||
);
|
||||
}, []);
|
||||
|
||||
const EmptyComponent = () => <></>;
|
||||
|
||||
return (
|
||||
<Tab.Navigator
|
||||
screenOptions={() => ({
|
||||
|
@ -169,7 +173,7 @@ export default function HomeTab({ navigation, route }) {
|
|||
/>
|
||||
<Tab.Screen
|
||||
name="Space"
|
||||
component={My}
|
||||
component={Space}
|
||||
options={{
|
||||
title: "空间",
|
||||
headerShown: false,
|
||||
|
@ -177,13 +181,13 @@ export default function HomeTab({ navigation, route }) {
|
|||
if (focused) {
|
||||
return (
|
||||
<Image
|
||||
source={require("../../assets/icon/others/myfocus.png")}
|
||||
source={require("../../assets/icon/others/space_focus.png")}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<Image
|
||||
source={require("../../assets/icon/others/myblur.png")}
|
||||
source={require("../../assets/icon/others/space_blur.png")}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@ -193,7 +197,7 @@ export default function HomeTab({ navigation, route }) {
|
|||
{isCreatePostTabVisible && (
|
||||
<Tab.Screen
|
||||
name="CreatePost"
|
||||
component={Stream}
|
||||
component={EmptyComponent}
|
||||
options={{
|
||||
title: "",
|
||||
headerShown: false,
|
||||
|
|
|
@ -160,16 +160,6 @@ export default function Posts({ navigation }) {
|
|||
</TabView.Item>
|
||||
</TabView>
|
||||
</View>
|
||||
{isStreamer && (
|
||||
<TouchableOpacity
|
||||
onPress={() => navigation.navigate("CreatePost")}
|
||||
style={tailwind("absolute right-3 bottom-5 rounded-full")}
|
||||
>
|
||||
<NativeImage
|
||||
source={require("../../assets/icon/others/createpost.png")}
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,111 @@
|
|||
import { View, Text, RefreshControl, TouchableOpacity } from "react-native";
|
||||
import React, { useState, useEffect, useCallback } from "react";
|
||||
import { useTailwind } from "tailwind-rn";
|
||||
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
||||
import Toast from "react-native-toast-message";
|
||||
import Empty from "../../../components/Empty";
|
||||
import { FlashList } from "@shopify/flash-list";
|
||||
import { useNavigation } from "@react-navigation/native";
|
||||
import SpaceCard from "../../../components/SpaceCard";
|
||||
|
||||
export default function SpaceList() {
|
||||
const blurhash = "LcKUTa%gOYWBYRt6xuoJo~s8V@fk";
|
||||
|
||||
const tailwind = useTailwind();
|
||||
const insets = useSafeAreaInsets();
|
||||
|
||||
const navigation = useNavigation();
|
||||
|
||||
const data = [
|
||||
{
|
||||
mid: 11,
|
||||
},
|
||||
{
|
||||
mid: 22,
|
||||
},
|
||||
{
|
||||
mid: 33,
|
||||
},
|
||||
{
|
||||
mid: 44,
|
||||
},
|
||||
];
|
||||
|
||||
const renderItem = ({ item }) => <SpaceCard data={data} />;
|
||||
|
||||
//数据为空时的组件
|
||||
const EmptyComponent = useCallback(() => {
|
||||
return (
|
||||
<View style={tailwind("flex flex-col justify-center items-center")}>
|
||||
<Empty type="nospace" />
|
||||
<TouchableOpacity
|
||||
onPress={() => navigation.navigate("Search")}
|
||||
style={{
|
||||
width: 190,
|
||||
height: 46,
|
||||
...tailwind(
|
||||
"flex items-center justify-center bg-[#2E2E2E] mt-3 rounded-full"
|
||||
),
|
||||
}}
|
||||
>
|
||||
<Text style={tailwind("text-white text-base font-medium")}>
|
||||
搜索空间
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
onPress={() => navigation.navigate("Stream")}
|
||||
style={{
|
||||
width: 190,
|
||||
height: 46,
|
||||
...tailwind(
|
||||
"flex items-center justify-center bg-[#2E2E2E] mt-2 rounded-full"
|
||||
),
|
||||
}}
|
||||
>
|
||||
<Text style={tailwind("text-white text-base font-medium")}>
|
||||
查看推荐
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
);
|
||||
}, []);
|
||||
|
||||
//下拉刷新
|
||||
const [refreshing, setRefreshing] = useState(false);
|
||||
const handleRefresh = async () => {
|
||||
setRefreshing(true);
|
||||
setRefreshing(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<View
|
||||
style={{
|
||||
paddingBottom: insets.bottom,
|
||||
paddingLeft: insets.left,
|
||||
paddingRight: insets.right,
|
||||
...tailwind("flex-1"),
|
||||
}}
|
||||
>
|
||||
<View style={tailwind("flex-1 px-2")}>
|
||||
<FlashList
|
||||
data={data}
|
||||
keyExtractor={(item) => item.mid}
|
||||
renderItem={renderItem}
|
||||
estimatedItemSize={287}
|
||||
initialNumToRender={12}
|
||||
numColumns={2}
|
||||
refreshControl={
|
||||
<RefreshControl
|
||||
colors={["#FF669E"]}
|
||||
tintColor="white"
|
||||
refreshing={refreshing}
|
||||
onRefresh={() => handleRefresh()}
|
||||
/>
|
||||
}
|
||||
onEndReached={() => {}}
|
||||
ListEmptyComponent={EmptyComponent}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
import { View, Text } from "react-native";
|
||||
import React from "react";
|
||||
|
||||
export default function SpacePosts() {
|
||||
return (
|
||||
<View>
|
||||
<Text>SpacePosts</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
import {
|
||||
View,
|
||||
TouchableOpacity,
|
||||
Image as NativeImage,
|
||||
Dimensions,
|
||||
} from "react-native";
|
||||
import React, { useState } from "react";
|
||||
import { useTailwind } from "tailwind-rn";
|
||||
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
||||
import { Tab, TabView } from "@rneui/themed";
|
||||
import SpaceList from "./SpaceList";
|
||||
import SpacePosts from "./SpacePosts";
|
||||
|
||||
export default function Space({ navigation }) {
|
||||
const tailwind = useTailwind();
|
||||
const insets = useSafeAreaInsets();
|
||||
const [index, setIndex] = useState(0);
|
||||
|
||||
//修复ios使用了tab组件闪退问题
|
||||
const [indicatorX, setIndicatorX] = useState(0);
|
||||
const windowWidth = Dimensions.get("window").width;
|
||||
const tabWidth = windowWidth / 5;
|
||||
|
||||
return (
|
||||
<View
|
||||
style={{
|
||||
paddingTop: insets.top,
|
||||
paddingLeft: insets.left,
|
||||
paddingRight: insets.right,
|
||||
...tailwind("flex flex-1"),
|
||||
}}
|
||||
>
|
||||
<View style={tailwind("flex pb-1 flex-row justify-between items-center")}>
|
||||
<View style={tailwind("flex w-2/5")}>
|
||||
<Tab
|
||||
value={index}
|
||||
onChange={(e) => {
|
||||
setIndex(e);
|
||||
setIndicatorX(e * tabWidth);
|
||||
}}
|
||||
dense
|
||||
indicatorStyle={{
|
||||
...tailwind("h-1 w-10 ml-4 rounded-full"),
|
||||
backgroundColor: "#FF7DCB",
|
||||
transform: [{ translateX: indicatorX }],
|
||||
}}
|
||||
>
|
||||
<Tab.Item
|
||||
titleStyle={
|
||||
index === 0
|
||||
? tailwind("text-white text-2xl font-medium")
|
||||
: { ...tailwind("text-2xl font-medium"), color: "#FFFFFF80" }
|
||||
}
|
||||
>
|
||||
空间
|
||||
</Tab.Item>
|
||||
<Tab.Item
|
||||
titleStyle={
|
||||
index === 1
|
||||
? tailwind("text-white text-2xl font-medium")
|
||||
: { ...tailwind("text-2xl font-medium"), color: "#FFFFFF80" }
|
||||
}
|
||||
>
|
||||
动态
|
||||
</Tab.Item>
|
||||
</Tab>
|
||||
</View>
|
||||
<TouchableOpacity
|
||||
style={tailwind(
|
||||
"flex items-center justify-center w-9 h-9 mr-4 bg-[#FFFFFF1A] rounded-full"
|
||||
)}
|
||||
onPress={() => navigation.navigate("Search")}
|
||||
>
|
||||
<NativeImage source={require("../../assets/icon/32DP/search.png")} />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
<View style={tailwind("flex flex-1 w-full")}>
|
||||
<TabView
|
||||
value={index}
|
||||
onChange={(e) => {
|
||||
setIndex(e);
|
||||
setIndicatorX(e * tabWidth);
|
||||
}}
|
||||
animationType="spring"
|
||||
>
|
||||
<TabView.Item style={tailwind("w-full flex-1")}>
|
||||
<SpaceList />
|
||||
</TabView.Item>
|
||||
<TabView.Item style={tailwind("w-full flex-1")}>
|
||||
<SpacePosts />
|
||||
</TabView.Item>
|
||||
</TabView>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,226 @@
|
|||
import {
|
||||
View,
|
||||
Text,
|
||||
Image as NativeImage,
|
||||
TouchableOpacity,
|
||||
Dimensions,
|
||||
ScrollView,
|
||||
} from "react-native";
|
||||
import React, { useEffect } from "react";
|
||||
import { useTailwind } from "tailwind-rn";
|
||||
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
||||
import Toast from "react-native-toast-message";
|
||||
import { Image } from "expo-image";
|
||||
import { useHeaderHeight } from "@react-navigation/elements";
|
||||
|
||||
const placeholder = "https://via.placeholder.com/1024x1024.png";
|
||||
|
||||
export default function SpaceIntroduce({ navigation, route }) {
|
||||
const blurhash = "LcKUTa%gOYWBYRt6xuoJo~s8V@fk";
|
||||
|
||||
const tailwind = useTailwind();
|
||||
const insets = useSafeAreaInsets();
|
||||
const headerHeight = useHeaderHeight();
|
||||
|
||||
//设置header右侧按钮功能
|
||||
useEffect(() => {
|
||||
navigation.setOptions({
|
||||
headerRight: () => (
|
||||
<TouchableOpacity onPress={() => console.log("space setting")}>
|
||||
<NativeImage
|
||||
source={require("../../assets/icon/others/setting.png")}
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
),
|
||||
});
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<View
|
||||
style={{
|
||||
paddingBottom: insets.bottom,
|
||||
paddingLeft: insets.left,
|
||||
paddingRight: insets.right,
|
||||
...tailwind("flex-1"),
|
||||
}}
|
||||
>
|
||||
<ScrollView>
|
||||
<View style={tailwind("absolute top-0 left-0")}>
|
||||
<Image
|
||||
source={placeholder}
|
||||
contentFit="cover"
|
||||
transition={1000}
|
||||
placeholder={blurhash}
|
||||
cachePolicy="disk"
|
||||
style={{
|
||||
aspectRatio: "25/17",
|
||||
...tailwind("w-full"),
|
||||
}}
|
||||
/>
|
||||
<View
|
||||
style={{
|
||||
backgroundColor: "#000000B2",
|
||||
...tailwind("absolute w-full h-full"),
|
||||
}}
|
||||
></View>
|
||||
</View>
|
||||
<View
|
||||
style={{
|
||||
marginTop: headerHeight,
|
||||
...tailwind("flex flex-row items-center px-4 h-24"),
|
||||
}}
|
||||
>
|
||||
<Image
|
||||
style={tailwind(
|
||||
"w-[4.6rem] h-[4.6rem] rounded-full border-2 border-white"
|
||||
)}
|
||||
source={placeholder}
|
||||
placeholder={blurhash}
|
||||
contentFit="cover"
|
||||
transition={1000}
|
||||
cachePolicy="disk"
|
||||
/>
|
||||
<View style={tailwind("flex flex-col shrink mx-2 justify-between")}>
|
||||
<Text
|
||||
style={{ fontSize: 22, ...tailwind("text-white font-medium") }}
|
||||
numberOfLines={1}
|
||||
ellipsizeMode="tail"
|
||||
>
|
||||
阿巴阿巴
|
||||
</Text>
|
||||
<View style={tailwind("flex-row flex-wrap mt-1.5")}>
|
||||
<View
|
||||
style={tailwind(
|
||||
"flex-row items-center py-0.5 px-2 mr-2 bg-[#FFFFFF1A] rounded-full"
|
||||
)}
|
||||
>
|
||||
<NativeImage
|
||||
source={require("../../assets/icon/12DP/ID.png")}
|
||||
/>
|
||||
<Text style={tailwind("text-white text-xs font-medium ml-0.5")}>
|
||||
666666
|
||||
</Text>
|
||||
</View>
|
||||
<View
|
||||
style={tailwind(
|
||||
"flex-row items-center py-0.5 px-2 mr-2 bg-[#FFFFFF1A] rounded-full"
|
||||
)}
|
||||
>
|
||||
<NativeImage
|
||||
source={require("../../assets/icon/12DP/edit.png")}
|
||||
/>
|
||||
<Text style={tailwind("text-white text-xs font-medium ml-0.5")}>
|
||||
24
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
<TouchableOpacity
|
||||
onPress={() => console.log("check wechat")}
|
||||
style={tailwind("flex flex-col items-center ml-auto")}
|
||||
>
|
||||
<NativeImage
|
||||
source={require("../../assets/icon/others/wechat_bg.png")}
|
||||
/>
|
||||
<Text style={tailwind("text-white text-xs font-medium mt-0.5")}>
|
||||
查看微信
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
<View
|
||||
style={tailwind(
|
||||
"flex flex-col w-full rounded-t-3xl bg-[#07050A] mt-4 p-4"
|
||||
)}
|
||||
>
|
||||
<View style={tailwind("flex flex-col items-start")}>
|
||||
<View>
|
||||
<Text style={tailwind("text-white text-lg font-medium mt-0.5")}>
|
||||
空间介绍
|
||||
</Text>
|
||||
<NativeImage
|
||||
style={{ right: -5, bottom: 1, ...tailwind("absolute") }}
|
||||
source={require("../../assets/icon/others/pinkline.png")}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
<Text style={tailwind("text-white text-base mt-4")}>
|
||||
阿巴阿巴阿巴阿巴阿巴阿巴阿巴阿巴阿巴阿巴阿巴阿巴阿巴阿巴阿巴阿巴阿
|
||||
</Text>
|
||||
<View style={tailwind("flex flex-row flex-wrap mt-2")}>
|
||||
<View style={tailwind("basis-1/3 pr-1")}>
|
||||
<Image
|
||||
style={{
|
||||
aspectRatio: "1/1",
|
||||
...tailwind("w-full rounded"),
|
||||
}}
|
||||
source={placeholder}
|
||||
placeholder={blurhash}
|
||||
contentFit="cover"
|
||||
transition={1000}
|
||||
cachePolicy="disk"
|
||||
/>
|
||||
</View>
|
||||
<View style={tailwind("basis-1/3 pr-1")}>
|
||||
<Image
|
||||
style={{
|
||||
aspectRatio: "1/1",
|
||||
...tailwind("w-full rounded"),
|
||||
}}
|
||||
source={placeholder}
|
||||
placeholder={blurhash}
|
||||
contentFit="cover"
|
||||
transition={1000}
|
||||
cachePolicy="disk"
|
||||
/>
|
||||
</View>
|
||||
<View style={tailwind("basis-1/3 pr-1")}>
|
||||
<Image
|
||||
style={{
|
||||
aspectRatio: "1/1",
|
||||
...tailwind("w-full rounded"),
|
||||
}}
|
||||
source={placeholder}
|
||||
placeholder={blurhash}
|
||||
contentFit="cover"
|
||||
transition={1000}
|
||||
cachePolicy="disk"
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
<View style={tailwind("flex flex-col items-start mt-8")}>
|
||||
<View>
|
||||
<Text style={tailwind("text-white text-lg font-medium mt-0.5")}>
|
||||
付费须知
|
||||
</Text>
|
||||
<NativeImage
|
||||
style={{ right: -5, bottom: 1, ...tailwind("absolute") }}
|
||||
source={require("../../assets/icon/others/pinkline.png")}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
<Text style={tailwind("text-white text-base mt-4")}>
|
||||
阿巴阿巴阿巴阿巴阿巴阿巴阿巴阿巴阿巴阿巴阿巴阿巴阿巴阿巴阿巴阿巴阿
|
||||
</Text>
|
||||
</View>
|
||||
</ScrollView>
|
||||
<View
|
||||
style={tailwind(
|
||||
"flex flex-row h-[4.5rem] py-2 px-6 items-center justify-center border-t border-[#FFFFFF26]"
|
||||
)}
|
||||
>
|
||||
<TouchableOpacity
|
||||
onPress={() => console.log("join")}
|
||||
style={tailwind(
|
||||
"flex flex-row items-center justify-center h-12 rounded-full px-10 bg-[#FF669E]"
|
||||
)}
|
||||
>
|
||||
<NativeImage source={require("../../assets/icon/others/money.png")} />
|
||||
<Text style={tailwind("text-base text-white font-medium")}>
|
||||
99元立即加入
|
||||
</Text>
|
||||
<NativeImage source={require("../../assets/icon/32DP/link.png")} />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,383 @@
|
|||
import {
|
||||
View,
|
||||
Text,
|
||||
Image as NativeImage,
|
||||
TouchableOpacity,
|
||||
useWindowDimensions,
|
||||
Animated,
|
||||
FlatList,
|
||||
PanResponder,
|
||||
ActivityIndicator,
|
||||
} from "react-native";
|
||||
import React, { useState, useEffect, useCallback, useRef } from "react";
|
||||
import { useTailwind } from "tailwind-rn";
|
||||
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
||||
import Toast from "react-native-toast-message";
|
||||
import { Image } from "expo-image";
|
||||
import { useHeaderHeight } from "@react-navigation/elements";
|
||||
import { TabView, SceneMap, TabBar } from "react-native-tab-view";
|
||||
import Empty from "../../components/Empty";
|
||||
|
||||
const placeholder = "https://via.placeholder.com/1024x1024.png";
|
||||
|
||||
export default function StreamerSpace({ navigation, route }) {
|
||||
const blurhash = "LcKUTa%gOYWBYRt6xuoJo~s8V@fk";
|
||||
const tailwind = useTailwind();
|
||||
const insets = useSafeAreaInsets();
|
||||
const headerHeight = useHeaderHeight();
|
||||
|
||||
const layout = useWindowDimensions();
|
||||
const [index, setIndex] = useState(0);
|
||||
const [routes] = useState([
|
||||
{ key: "all", title: "全部" },
|
||||
{ key: "tiefen", title: "铁粉专享" },
|
||||
{ key: "chaofen", title: "超粉专享" },
|
||||
]);
|
||||
|
||||
const data = [
|
||||
{ mid: 111 },
|
||||
{ mid: 222 },
|
||||
{ mid: 333 },
|
||||
{ mid: 444 },
|
||||
{ mid: 555 },
|
||||
{ mid: 666 },
|
||||
{ mid: 777 },
|
||||
{ mid: 888 },
|
||||
];
|
||||
|
||||
const PostComponent = () => (
|
||||
<View style={tailwind("w-full h-24 mt-4 bg-white rounded-2xl")}></View>
|
||||
);
|
||||
const renderItem = ({ item }) => <PostComponent />;
|
||||
|
||||
const AllRoute = () => (
|
||||
<FlatList
|
||||
data={data}
|
||||
renderItem={renderItem}
|
||||
initialNumToRender={4}
|
||||
onScroll={(event) => {
|
||||
if (event.nativeEvent.contentOffset.y === 0)
|
||||
viewTranslateYRef.current = -199;
|
||||
}}
|
||||
ListFooterComponent={() => (
|
||||
<View style={{ paddingBottom: 50 }}>
|
||||
<ActivityIndicator style={tailwind("my-4")} size="large" />
|
||||
</View>
|
||||
)}
|
||||
ListEmptyComponent={<Empty type="nodata" />}
|
||||
/>
|
||||
);
|
||||
const TiefenRoute = () => (
|
||||
<View style={{ flex: 1, backgroundColor: "#673ab7" }} />
|
||||
);
|
||||
const ChaofenRoute = () => (
|
||||
<View style={{ flex: 1, backgroundColor: "#84cc16" }} />
|
||||
);
|
||||
|
||||
const renderScene = SceneMap({
|
||||
all: AllRoute,
|
||||
tiefen: TiefenRoute,
|
||||
chaofen: ChaofenRoute,
|
||||
});
|
||||
|
||||
const renderIndicator = (props) => {
|
||||
const { position, navigationState, getTabWidth } = props;
|
||||
const inputRange = [0, 1];
|
||||
const translateX = position.interpolate({
|
||||
inputRange: inputRange,
|
||||
outputRange: inputRange.map((x) => {
|
||||
return x * getTabWidth(navigationState.index);
|
||||
}),
|
||||
});
|
||||
return (
|
||||
<Animated.View
|
||||
style={{
|
||||
width: `${100 / navigationState.routes.length}%`,
|
||||
transform: [
|
||||
{
|
||||
translateX,
|
||||
},
|
||||
],
|
||||
paddingBottom: 12,
|
||||
...tailwind("flex flex-1 items-center justify-end"),
|
||||
}}
|
||||
>
|
||||
<NativeImage
|
||||
source={require("../../assets/icon/others/pinkline.png")}
|
||||
/>
|
||||
</Animated.View>
|
||||
);
|
||||
};
|
||||
|
||||
const renderTabBar = (props) => (
|
||||
<TabBar
|
||||
{...props}
|
||||
style={tailwind("bg-transparent")}
|
||||
labelStyle={tailwind("text-base font-medium")}
|
||||
renderIndicator={renderIndicator}
|
||||
/>
|
||||
);
|
||||
|
||||
//设置header右侧按钮功能
|
||||
useEffect(() => {
|
||||
navigation.setOptions({
|
||||
headerRight: () => (
|
||||
<TouchableOpacity onPress={() => console.log("space setting")}>
|
||||
<NativeImage
|
||||
source={require("../../assets/icon/others/setting.png")}
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
),
|
||||
});
|
||||
}, []);
|
||||
|
||||
const panResponder = useRef(
|
||||
PanResponder.create({
|
||||
onStartShouldSetPanResponder: () => {
|
||||
if (viewTranslateYRef.current === -200) return false;
|
||||
return true;
|
||||
},
|
||||
onPanResponderMove: (_, gesture) => {
|
||||
const { dy } = gesture;
|
||||
if (dy < 0) {
|
||||
pan.setValue(Math.max(dy + viewTranslateYRef.current, -200));
|
||||
} else {
|
||||
pan.setValue(Math.min(dy + viewTranslateYRef.current, 0));
|
||||
}
|
||||
},
|
||||
onPanResponderRelease: (_, gesture) => {
|
||||
const { dy } = gesture;
|
||||
if (dy < 0) {
|
||||
viewTranslateYRef.current = Math.max(
|
||||
dy + viewTranslateYRef.current,
|
||||
-200
|
||||
);
|
||||
} else {
|
||||
viewTranslateYRef.current = Math.min(
|
||||
dy + viewTranslateYRef.current,
|
||||
0
|
||||
);
|
||||
}
|
||||
},
|
||||
})
|
||||
).current;
|
||||
|
||||
const pan = useRef(new Animated.Value(0)).current;
|
||||
const viewTranslateYRef = useRef(null);
|
||||
|
||||
return (
|
||||
<View
|
||||
style={{
|
||||
paddingLeft: insets.left,
|
||||
paddingRight: insets.right,
|
||||
...tailwind("flex-1"),
|
||||
}}
|
||||
>
|
||||
<View style={tailwind("absolute top-0 left-0")}>
|
||||
<Image
|
||||
source={placeholder}
|
||||
contentFit="cover"
|
||||
transition={1000}
|
||||
placeholder={blurhash}
|
||||
cachePolicy="disk"
|
||||
style={{
|
||||
aspectRatio: "15/13",
|
||||
...tailwind("w-full"),
|
||||
}}
|
||||
/>
|
||||
<View
|
||||
style={{
|
||||
backgroundColor: "#000000B2",
|
||||
...tailwind("absolute w-full h-full"),
|
||||
}}
|
||||
></View>
|
||||
</View>
|
||||
<View
|
||||
style={{
|
||||
marginTop: headerHeight,
|
||||
...tailwind("flex flex-row items-center px-4 h-24"),
|
||||
}}
|
||||
>
|
||||
<Image
|
||||
style={tailwind(
|
||||
"w-[4.6rem] h-[4.6rem] rounded-full border-2 border-white"
|
||||
)}
|
||||
source={placeholder}
|
||||
placeholder={blurhash}
|
||||
contentFit="cover"
|
||||
transition={1000}
|
||||
cachePolicy="disk"
|
||||
/>
|
||||
<View style={tailwind("flex flex-col shrink mx-2 justify-between")}>
|
||||
<Text
|
||||
style={{ fontSize: 22, ...tailwind("text-white font-medium") }}
|
||||
numberOfLines={1}
|
||||
ellipsizeMode="tail"
|
||||
>
|
||||
阿巴阿巴阿巴阿巴阿巴阿巴
|
||||
</Text>
|
||||
<View style={tailwind("flex-row flex-wrap mt-1.5")}>
|
||||
<View
|
||||
style={tailwind(
|
||||
"flex-row items-center py-0.5 px-2 mr-2 bg-[#FFFFFF1A] rounded-full"
|
||||
)}
|
||||
>
|
||||
<NativeImage source={require("../../assets/icon/12DP/ID.png")} />
|
||||
<Text style={tailwind("text-white text-xs font-medium ml-0.5")}>
|
||||
666666
|
||||
</Text>
|
||||
</View>
|
||||
<View
|
||||
style={tailwind(
|
||||
"flex-row items-center py-0.5 px-2 mr-2 bg-[#FFFFFF1A] rounded-full"
|
||||
)}
|
||||
>
|
||||
<NativeImage
|
||||
source={require("../../assets/icon/12DP/edit.png")}
|
||||
/>
|
||||
<Text style={tailwind("text-white text-xs font-medium ml-0.5")}>
|
||||
24
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
<TouchableOpacity
|
||||
style={tailwind(
|
||||
"flex items-center justify-center ml-auto h-8 px-4 bg-[#FF669E] rounded-full"
|
||||
)}
|
||||
>
|
||||
<Text style={tailwind("text-white text-sm font-medium")}>分享</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
<View style={{ gap: 22, ...tailwind("flex flex-row px-6 mt-2") }}>
|
||||
<TouchableOpacity
|
||||
onPress={() => console.log("check wechat")}
|
||||
style={tailwind("flex flex-col items-center")}
|
||||
>
|
||||
<NativeImage
|
||||
source={require("../../assets/icon/others/wechat_bg.png")}
|
||||
/>
|
||||
<Text style={tailwind("text-white text-xs font-medium mt-0.5")}>
|
||||
查看微信
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
onPress={() => console.log("become tiefen")}
|
||||
style={tailwind("flex flex-col items-center")}
|
||||
>
|
||||
<NativeImage
|
||||
source={require("../../assets/icon/others/tiefen_bg.png")}
|
||||
/>
|
||||
<View style={tailwind("flex flex-col items-center")}>
|
||||
<Text style={tailwind("text-white text-xs font-medium mt-0.5")}>
|
||||
成为铁粉
|
||||
</Text>
|
||||
<Text
|
||||
style={{
|
||||
fontSize: 10,
|
||||
...tailwind("text-[#FFFFFF80] font-medium mt-0.5"),
|
||||
}}
|
||||
>
|
||||
(88/999)
|
||||
</Text>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
onPress={() => console.log("become chaofen")}
|
||||
style={tailwind("flex flex-col items-center")}
|
||||
>
|
||||
<NativeImage
|
||||
source={require("../../assets/icon/others/chaofen_bg.png")}
|
||||
/>
|
||||
<Text style={tailwind("text-white text-xs font-medium mt-0.5")}>
|
||||
成为超粉
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
onPress={() => console.log("report")}
|
||||
style={tailwind("flex flex-col items-center")}
|
||||
>
|
||||
<NativeImage
|
||||
source={require("../../assets/icon/others/report_bg.png")}
|
||||
/>
|
||||
<Text style={tailwind("text-white text-xs font-medium mt-0.5")}>
|
||||
举报
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
<Animated.View
|
||||
style={{
|
||||
transform: [
|
||||
{
|
||||
translateY: pan,
|
||||
},
|
||||
],
|
||||
height: layout.height - headerHeight - 72 - insets.bottom + 50,
|
||||
...tailwind("flex rounded-t-3xl bg-[#07050A] mt-6 px-4"),
|
||||
}}
|
||||
{...panResponder.panHandlers}
|
||||
>
|
||||
<TabView
|
||||
navigationState={{ index, routes }}
|
||||
swipeEnabled={false}
|
||||
renderScene={renderScene}
|
||||
renderTabBar={renderTabBar}
|
||||
onIndexChange={setIndex}
|
||||
initialLayout={{ width: layout.width }}
|
||||
/>
|
||||
</Animated.View>
|
||||
<View
|
||||
style={{
|
||||
...tailwind(
|
||||
"absolute bottom-0 flex flex-row w-full py-3 px-6 justify-around border-t border-[#FFFFFF26] bg-[#07050A]"
|
||||
),
|
||||
height: 72 + insets.bottom,
|
||||
}}
|
||||
>
|
||||
<TouchableOpacity
|
||||
onPress={() => console.log("check wechat")}
|
||||
style={tailwind("flex flex-col items-center")}
|
||||
>
|
||||
<NativeImage
|
||||
source={require("../../assets/icon/others/wechat.png")}
|
||||
/>
|
||||
<Text style={tailwind("text-white text-xs font-medium mt-0.5")}>
|
||||
查看微信
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
onPress={() => console.log("become tiefen")}
|
||||
style={tailwind("flex flex-col items-center")}
|
||||
>
|
||||
<NativeImage
|
||||
source={require("../../assets/icon/others/tiefen.png")}
|
||||
/>
|
||||
<View style={tailwind("flex flex-col items-center")}>
|
||||
<Text style={tailwind("text-white text-xs font-medium mt-0.5")}>
|
||||
成为铁粉
|
||||
</Text>
|
||||
<Text
|
||||
style={{
|
||||
fontSize: 10,
|
||||
...tailwind("text-[#FFFFFF80] font-medium mt-0.5"),
|
||||
}}
|
||||
>
|
||||
(88/999)
|
||||
</Text>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
onPress={() => console.log("become chaofen")}
|
||||
style={tailwind("flex flex-col items-center")}
|
||||
>
|
||||
<NativeImage
|
||||
source={require("../../assets/icon/others/chaofen.png")}
|
||||
/>
|
||||
<Text style={tailwind("text-white text-xs font-medium mt-0.5")}>
|
||||
成为超粉
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
12
yarn.lock
12
yarn.lock
|
@ -6142,6 +6142,11 @@ react-native-lightbox-v2@0.9.0:
|
|||
resolved "https://registry.npmmirror.com/react-native-lightbox-v2/-/react-native-lightbox-v2-0.9.0.tgz#b97be4d892ebb959069c451948b11da390bc46d8"
|
||||
integrity sha512-Fc5VFHFj2vokS+OegyTsANKb1CYoUlOtAv+EBH5wtpJn1b5cey6jVXH7136G5+8OC9JmKWSgKHc5thFwOoZTUg==
|
||||
|
||||
react-native-pager-view@6.2.0:
|
||||
version "6.2.0"
|
||||
resolved "https://registry.npmmirror.com/react-native-pager-view/-/react-native-pager-view-6.2.0.tgz#51380d93fbe47f6380dc71d613a787bf27a4ca37"
|
||||
integrity sha512-pf9OnL/Tkr+5s4Gjmsn7xh91PtJLDa6qxYa/bmtUhd/+s4cQdWQ8DIFoOFghwZIHHHwVdWtoXkp6HtpjN+r20g==
|
||||
|
||||
react-native-parsed-text@0.0.22:
|
||||
version "0.0.22"
|
||||
resolved "https://registry.npmmirror.com/react-native-parsed-text/-/react-native-parsed-text-0.0.22.tgz#a23c756eaa5d6724296814755085127f9072e5f5"
|
||||
|
@ -6197,6 +6202,13 @@ react-native-swiper@^1.6.0:
|
|||
dependencies:
|
||||
prop-types "^15.5.10"
|
||||
|
||||
react-native-tab-view@^3.5.2:
|
||||
version "3.5.2"
|
||||
resolved "https://registry.npmmirror.com/react-native-tab-view/-/react-native-tab-view-3.5.2.tgz#2789b8af6148b16835869566bf13dc3b0e6c1b46"
|
||||
integrity sha512-nE5WqjbeEPsWQx4mtz81QGVvgHRhujTNIIZiMCx3Bj6CBFDafbk7XZp9ocmtzXUQaZ4bhtVS43R4FIiR4LboJw==
|
||||
dependencies:
|
||||
use-latest-callback "^0.1.5"
|
||||
|
||||
react-native-toast-message@^2.1.6:
|
||||
version "2.1.6"
|
||||
resolved "https://registry.npmmirror.com/react-native-toast-message/-/react-native-toast-message-2.1.6.tgz#322827c66901fa22cb3db614c7383cc717f5bbe2"
|
||||
|
|
Loading…
Reference in New Issue