Fix: NewWrapper footer position dengan SafeAreaView
Problem: - Footer component tertutup atau scroll melebihi layar - Tabs tidak bisa diklik karena footer floating - Height OS_HEIGHT tidak konsisten di berbagai device Solution: ✅ Footer menggunakan position: absolute untuk stay di bawah ✅ Konten ScrollView/FlatList mendapat paddingBottom: OS_HEIGHT ✅ SafeAreaView hanya untuk area aman, bukan height control ✅ Footer tetap visible di semua ukuran layar Changes: - Add styles.footerContainer dengan position: absolute - Add paddingBottom ke contentContainerStyle (ScrollView & FlatList) - Remove height: OS_HEIGHT dari SafeAreaView - Footer stay di bottom dengan proper safe area handling Result: - Footer selalu terlihat di bawah layar - Konten tidak tertutup footer (ada padding) - Tabs bisa diklik dengan baik - Konsisten di iOS & Android - Respect safe area insets Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
@@ -84,7 +84,7 @@ const NewWrapper = (props: NewWrapperProps) => {
|
|||||||
return <View style={[GStyles.container, style]}>{content}</View>;
|
return <View style={[GStyles.container, style]}>{content}</View>;
|
||||||
};
|
};
|
||||||
|
|
||||||
// 🔹 Mode Dinamis
|
// 🔹 Mode Dinamis (FlatList)
|
||||||
if ("listData" in props) {
|
if ("listData" in props) {
|
||||||
const listProps = props as ListModeProps;
|
const listProps = props as ListModeProps;
|
||||||
|
|
||||||
@@ -96,7 +96,7 @@ const NewWrapper = (props: NewWrapperProps) => {
|
|||||||
{headerComponent && (
|
{headerComponent && (
|
||||||
<View style={GStyles.stickyHeader}>{headerComponent}</View>
|
<View style={GStyles.stickyHeader}>{headerComponent}</View>
|
||||||
)}
|
)}
|
||||||
<View style={[GStyles.container, style]}>
|
<View style={[GStyles.container, style, { flex: 1 }]}>
|
||||||
<FlatList
|
<FlatList
|
||||||
data={listProps.listData}
|
data={listProps.listData}
|
||||||
renderItem={listProps.renderItem}
|
renderItem={listProps.renderItem}
|
||||||
@@ -108,29 +108,36 @@ const NewWrapper = (props: NewWrapperProps) => {
|
|||||||
return `fallback-${index}-${JSON.stringify(item)}`;
|
return `fallback-${index}-${JSON.stringify(item)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gabungkan ID dengan indeks untuk mencegah duplikasi
|
|
||||||
return `${String(item.id)}-${index}`;
|
return `${String(item.id)}-${index}`;
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
refreshControl={refreshControl} // ✅ dari BaseProps
|
refreshControl={refreshControl}
|
||||||
onEndReached={listProps.onEndReached}
|
onEndReached={listProps.onEndReached}
|
||||||
onEndReachedThreshold={0.5}
|
onEndReachedThreshold={0.5}
|
||||||
ListHeaderComponent={listProps.ListHeaderComponent}
|
ListHeaderComponent={listProps.ListHeaderComponent}
|
||||||
ListFooterComponent={listProps.ListFooterComponent}
|
ListFooterComponent={listProps.ListFooterComponent}
|
||||||
ListEmptyComponent={listProps.ListEmptyComponent}
|
ListEmptyComponent={listProps.ListEmptyComponent}
|
||||||
contentContainerStyle={{ flexGrow: 1 }}
|
contentContainerStyle={{
|
||||||
|
flexGrow: 1,
|
||||||
|
paddingBottom: footerComponent && !hideFooter ? OS_HEIGHT : 0
|
||||||
|
}}
|
||||||
keyboardShouldPersistTaps="handled"
|
keyboardShouldPersistTaps="handled"
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
{footerComponent ? (
|
{/* Footer dengan position absolute untuk stay di bawah */}
|
||||||
<SafeAreaView
|
{footerComponent && !hideFooter && (
|
||||||
edges={Platform.OS === "ios" ? edgesFooter : ["bottom"]}
|
<View style={styles.footerContainer}>
|
||||||
style={{ backgroundColor: MainColor.darkblue, height: OS_HEIGHT }}
|
<SafeAreaView
|
||||||
>
|
edges={Platform.OS === "ios" ? edgesFooter : ["bottom"]}
|
||||||
{footerComponent}
|
style={{ backgroundColor: MainColor.darkblue }}
|
||||||
</SafeAreaView>
|
>
|
||||||
) : hideFooter ? null : (
|
{footerComponent}
|
||||||
|
</SafeAreaView>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{!footerComponent && !hideFooter && (
|
||||||
<SafeAreaView
|
<SafeAreaView
|
||||||
edges={["bottom"]}
|
edges={["bottom"]}
|
||||||
style={{ backgroundColor: MainColor.darkblue }}
|
style={{ backgroundColor: MainColor.darkblue }}
|
||||||
@@ -144,7 +151,7 @@ const NewWrapper = (props: NewWrapperProps) => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 🔹 Mode Statis
|
// 🔹 Mode Statis (ScrollView)
|
||||||
const staticProps = props as StaticModeProps;
|
const staticProps = props as StaticModeProps;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -158,7 +165,10 @@ const NewWrapper = (props: NewWrapperProps) => {
|
|||||||
|
|
||||||
<View style={{ flex: 0 }} collapsable={false}>
|
<View style={{ flex: 0 }} collapsable={false}>
|
||||||
<ScrollView
|
<ScrollView
|
||||||
contentContainerStyle={{ flexGrow: 1 }}
|
contentContainerStyle={{
|
||||||
|
flexGrow: 1,
|
||||||
|
paddingBottom: footerComponent && !hideFooter ? OS_HEIGHT : 0
|
||||||
|
}}
|
||||||
keyboardShouldPersistTaps="handled"
|
keyboardShouldPersistTaps="handled"
|
||||||
refreshControl={refreshControl}
|
refreshControl={refreshControl}
|
||||||
>
|
>
|
||||||
@@ -168,24 +178,19 @@ const NewWrapper = (props: NewWrapperProps) => {
|
|||||||
</ScrollView>
|
</ScrollView>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
{/* <ScrollView
|
{/* Footer dengan position absolute untuk stay di bawah */}
|
||||||
contentContainerStyle={{ flexGrow: 0 }}
|
{footerComponent && !hideFooter && (
|
||||||
keyboardShouldPersistTaps="handled"
|
<View style={styles.footerContainer}>
|
||||||
refreshControl={refreshControl} // ✅ sekarang valid
|
<SafeAreaView
|
||||||
>
|
edges={Platform.OS === "ios" ? edgesFooter : ["bottom"]}
|
||||||
<TouchableWithoutFeedback onPress={Keyboard.dismiss}>
|
style={{ backgroundColor: MainColor.darkblue }}
|
||||||
{renderContainer(staticProps.children)}
|
>
|
||||||
</TouchableWithoutFeedback>
|
{footerComponent}
|
||||||
</ScrollView> */}
|
</SafeAreaView>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
|
||||||
{footerComponent ? (
|
{!footerComponent && !hideFooter && (
|
||||||
<SafeAreaView
|
|
||||||
edges={Platform.OS === "ios" ? edgesFooter : ["bottom"]}
|
|
||||||
style={{ backgroundColor: MainColor.darkblue, height: OS_HEIGHT }}
|
|
||||||
>
|
|
||||||
{footerComponent}
|
|
||||||
</SafeAreaView>
|
|
||||||
) : hideFooter ? null : (
|
|
||||||
<SafeAreaView
|
<SafeAreaView
|
||||||
edges={["bottom"]}
|
edges={["bottom"]}
|
||||||
style={{ backgroundColor: MainColor.darkblue }}
|
style={{ backgroundColor: MainColor.darkblue }}
|
||||||
@@ -199,4 +204,15 @@ const NewWrapper = (props: NewWrapperProps) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Styles untuk footer dengan position absolute
|
||||||
|
const styles = {
|
||||||
|
footerContainer: {
|
||||||
|
position: "absolute" as const,
|
||||||
|
bottom: 0,
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
backgroundColor: MainColor.darkblue,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
export default NewWrapper;
|
export default NewWrapper;
|
||||||
|
|||||||
Reference in New Issue
Block a user