๐ ์คํฌ๋ฆฐ์ท/ScreenShot
๊ตฌ๊ธ๋๋ผ์ด๋ธ/Google Drive :
https://drive.google.com/drive/folders/1hhhIYmU8kSGOUTN9wd7H9igSppl6AE71?usp=drive_link
1.react-native-freelifemakers-ui NPM ๋ชจ๋ ์ค์นํ๊ธฐ / react-native-freelifemakers-ui NPM Module Install
# npm install react-native-freelifemakers-ui
2.์์กด์ฑ ๋ชจ๋ ์ค์น / peerModule install
— FlmBottomSheet๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํด์ ๋ฐ๋์ ์ค์นํด์ผ ํ๋ ๋ชจ๋์
๋๋ค.
This is a module that must be installed to use FlmBottomSheet.
1)React-Native Expo
— react-native-freelifemakers-ui ์ด ๋ชจ๋์ ์ฌ์ฉํ๊ธฐ ์ํด์๋ ์๋ ๋๊ฐ์ ๋ชจ๋์ ๋ฐ๋์ ์ค์นํด์ผ ํฉ๋๋ค.
To use this module, you must install the following two modules: react-native-freelifemakers-ui
— ๋ฆฌ์กํธ ๋ค์ดํฐ๋ธ ์์คํฌ๋ ๋ฐ๋์ react-native-reanimated@3.17.4 ๋ฒ์ ์ ์ค์น ํฉ๋๋ค.
React Native Expo requires react-native-reanimated@3.17.4 to be installed.
— ์์คํฌ ํ๋ก์ ํธ์ 3.17.4๋ฒ์ ์ด ๊ฐ์ฅ ํธํ์ด ์๋๋ฉฐ ์ด๊ฒ๋ณด๋ค ์์๋ฒ์ ์ค์น์ FlmBanner๊ฐ ๋์ํ์ง ์์ ์ ์์ต๋๋ค.
Expo Project is most compatible with version 3.17.4, and the FlmBanner may not work when installing a higher version.
# npm install react-native-gesture-handler
# npm install react-native-reanimated@3.17.4
-babel.config.js
–> ์ด ํ์ผ์ด ์์ผ๋ฉด ํ์ผ์ ์ง์ ๋ง๋ง๋๋ค.
If this file does not exist, create it yourself.
–> ํ๋ก์ ํธ ํด๋ ๋ด package.jsonํ์ผ๊ณผ ๋์ผํ ์์น์ ๋ง๋ค๋ฉด๋ฉ๋๋ค.
Just create it in the same location as the package.json file in your project folder.
–> ์๋์ reanimated๋ชจ๋์ ์ํด ๋ค์๊ณผ ๊ฐ์ ์ค์ ์ ์ ์ฉํฉ๋๋ค.
Apply the following settings for the reanimated module below:
// babel.config.js
module.exports = function(api) {
api.cache(true);
return {
presets: ['babel-preset-expo'],
plugins: [
'react-native-reanimated/plugin', //react-native-reanimated module setting
],
};
};
2)React-Native CLI
— react-native-freelifemakers-ui ์ด ๋ชจ๋์ ์ฌ์ฉํ๊ธฐ ์ํด์๋ ์๋ ๋๊ฐ์ ๋ชจ๋์ ๋ฐ๋์ ์ค์นํด์ผ ํฉ๋๋ค.
To use this module, you must install the following two modules: react-native-freelifemakers-ui
— ์๋๋ก์ด๋์์๋ react-native-reanimated๋ชจ๋์ด ์์ ์ ์ผ๋ก ๋์ํ์ง ์๋ ๊ฒฝ์ฐ๊ฐ ์์ต๋๋ค.
On Android, the react-native-reanimated module may not work reliably.
— IOS์์๋ ์ ์์ ์ผ๋ก ์๋ํฉ๋๋ค.
It works fine on iOS.
— ๋ฆฌ์กํธ๋ค์ดํฐ๋ธ CLI์์๋ react-native-reanimated ์ต์ ๋ฒ์ ์ ์ค์นํด๋ ๋ฉ๋๋ค.
For React Native CLI, you can install the latest version of react-native-reanimated.
— ํ์ฌ 3.18.0๋ฒ์ ์ค์นํด์ ํ
์คํธ ํด๋ณธ ๊ฒฐ๊ณผ ์ ์๋ ํฉ๋๋ค.
I have currently installed version 3.18.0 and tested it and it works well.
# npm install react-native-gesture-handler
# npm install react-native-reanimated
-babel.config.js
–> ์ด ํ์ผ์ด ์์ผ๋ฉด ํ์ผ์ ์ง์ ๋ง๋ง๋๋ค.
If this file does not exist, create it yourself.
–> ํ๋ก์ ํธ ํด๋ ๋ด package.jsonํ์ผ๊ณผ ๋์ผํ ์์น์ ๋ง๋ค๋ฉด๋ฉ๋๋ค.
Just create it in the same location as the package.json file in your project folder.
–> ์๋์ reanimated๋ชจ๋์ ์ํด ๋ค์๊ณผ ๊ฐ์ ์ค์ ์ ์ ์ฉํฉ๋๋ค.
Apply the following settings for the reanimated module below:
// babel.config.js
module.exports = {
presets: ['module:@react-native/babel-preset'],
plugins: ['react-native-reanimated/plugin'], //react-native-reanimated module setting
};
2.์ฌ์ฉํ๊ธฐ / Usage
- ๋ฐฐ๋๋ฅผ ์ธ๋ถ ๋ฒํผ์ผ๋ก ์ด๊ณ ๋ซ์ ์ ์๊ณ ๋ฐฐ๋ ๋ด์ ๋ซ๊ธฐ ๋ฒํผ ํญํ ๊ฒฝ์ฐ ๋ฐฐ๋๋ฅผ ๊ฐ๋ณ์ ์ผ๋ก ๋ซ์ ์ ์์ต๋๋ค.
Banners can be opened and closed with external buttons, and banners can be closed individually by tapping the close button within the banner. - ํ
์คํธ ๋ฐฐ๋, ์ด๋ฏธ์ง ๋ฐฐ๋, ์ปค์คํ
๋ฐฐ๋๊ฐ ์์ต๋๋ค.
There are text banners, image banners, and custom banners. - ์๋์ ์ฝ๋๋ฅผ ๋ณต์ฌํด์ ์คํํด๋ณด๊ณ ์ ์๋ํ๋ฉด ์์ ํด์ ์ฌ์ฉํ์๋ฉด ๋ฉ๋๋ค.
Please copy and run the code below. If it works well, you can modify it and use it.
1)ํ ์คํธ ๋ฐฐ๋ / Text Banner
<FlmBanner
type="text"
data={{
message: "ํ
์คํธ๋ฐฐ๋ (์ ๋๋ฉ์ด์
์ ์ฉ)/Text Banner (Animated)",
id: "promo1",
}}
onPress={() =>
Alert.alert(
"ํ
์คํธ ๋ฐฐ๋/Text Banner",
"ํ
์คํธ ๋ฐฐ๋๊ฐ ํด๋ฆญ๋์์ต๋๋ค/Text banner clicked",
)
}
isVisible={isTextBannerVisible} // ๊ฐ๋ณ isVisible prop ์ ๋ฌ / Passing individual isVisible props
onClose={handleCloseTextBanner} // ๋ซ๊ธฐ ์ฝ๋ฐฑ ํจ์ ์ ๋ฌ / Passing a close callback function
animationMaxHeight={80}
style={{
backgroundColor: "#e0f7fa",
borderColor: "#00bcd4",
borderWidth: 1,
}}
textStyle={{ color: "#006064", fontSize: 17 }}
/>
2)์ด๋ฏธ์ง ๋ฐฐ๋ / Image Banner
<FlmBanner
type="image"
data={{
imageUrl: "https://picsum.photos/600/400",
title:
"์ด๋ฏธ์ง๋ฐฐ๋ 1! (์ ๋๋ฉ์ด์
์ ์ฉ)/Image Banner 1! (Animation applied)",
id: "product2",
}}
onPress={() =>
Alert.alert(
"์ด๋ฏธ์ง ๋ฐฐ๋ 1/Image Banner 1",
"์ด๋ฏธ์ง ๋ฐฐ๋ 1์ด ํด๋ฆญ๋์์ต๋๋ค!/Image banner 1 has been clicked!",
)
}
isVisible={isImageBanner1Visible} // ๊ฐ๋ณ isVisible prop ์ ๋ฌ
onClose={handleCloseImageBanner1} // ๋ซ๊ธฐ ์ฝ๋ฐฑ ํจ์ ์ ๋ฌ
style={{ borderColor: "#ffeb3b", borderWidth: 2 }}
imageStyle={{ borderRadius: 15 }}
titleStyle={{ color: "#4a148c", fontSize: 20, textShadowRadius: 8 }}
/>
3)์ปค์คํ ๋ฐฐ๋ / Custom Banner
<FlmBanner
type="image"
data={{
imageUrl:
"https://avatars3.githubusercontent.com/u/17571969?s=400&v=4",
title:
"์ปค์คํ
๋ฐฐ๋ 2! (์ ๋๋ฉ์ด์
์ ์ฉ) / Custom Banner 2! (Animated)",
id: "product3",
}}
onPress={() =>
Alert.alert(
"์ด๋ฏธ์ง ๋ฐฐ๋ 2 / Image Banner 2",
"์ด๋ฏธ์ง ๋ฐฐ๋ 2๊ฐ ํด๋ฆญ๋์์ต๋๋ค! / Image banner 2 was clicked!",
)
}
isVisible={isImageBanner2Visible} // ๊ฐ๋ณ isVisible prop ์ ๋ฌ / Passing individual isVisible props
onClose={handleCloseImageBanner2} // ๋ซ๊ธฐ ์ฝ๋ฐฑ ํจ์ ์ ๋ฌ / Passing a close callback function
style={{ backgroundColor: "#f3e5f5", borderRadius: 20 }}
imageStyle={{ opacity: 0.9 }}
titleStyle={{ color: "#4a148c", fontSize: 22, fontWeight: "normal" }}
/>
3.์์ ์ฝ๋ / Example code
// FlmBannerApp.js
import React, { useState } from "react";
import {
SafeAreaView,
ScrollView,
View,
StyleSheet,
Text,
Alert,
} from "react-native";
import { FlmBanner, FlmButton, FlmText } from "react-native-freelifemakers-ui";
const FlmBannerApp = () => {
// ๊ฐ ๋ฐฐ๋์ ๊ฐ์์ฑ์ ์ํ ๊ฐ๋ณ ์ํ ์ ์ / Define individual states for visibility of each banner
const [isTextBannerVisible, setIsTextBannerVisible] = useState(true);
const [isImageBanner1Visible, setIsImageBanner1Visible] = useState(true);
const [isImageBanner2Visible, setIsImageBanner2Visible] = useState(true);
// ๊ฐ ๋ฐฐ๋์ ๋ซ๊ธฐ ํธ๋ค๋ฌ ํจ์ / Close handler function for each banner
const handleCloseTextBanner = () => {
setIsTextBannerVisible(false);
console.log("ํ
์คํธ ๋ฐฐ๋ ๋ซํ / Text Banner Close");
};
const handleCloseImageBanner1 = () => {
setIsImageBanner1Visible(false);
console.log("์ด๋ฏธ์ง ๋ฐฐ๋ 1 ๋ซํ / Image Banner 1 Close");
};
const handleCloseImageBanner2 = () => {
setIsImageBanner2Visible(false);
console.log("์ด๋ฏธ์ง ๋ฐฐ๋ 2 ๋ซํ / Image Banner 2 Close");
};
// ๋ชจ๋ ๋ฐฐ๋๋ฅผ ๋์์ ํ ๊ธํ๋ ํจ์ (์ธ๋ถ ๋ฒํผ์ฉ) / Function to toggle all banners simultaneously (for external buttons)
const handleToggleAllBanners = () => {
setIsTextBannerVisible((prev) => !prev);
setIsImageBanner1Visible((prev) => !prev);
setIsImageBanner2Visible((prev) => !prev);
console.log(
`๋ชจ๋ ๋ฐฐ๋ ์ํ ํ ๊ธ/Toggle all banner states: ${isTextBannerVisible ? "์จ๊น/hidden" : "์คํ/open"}`,
);
};
return (
<SafeAreaView style={styles.container}>
<ScrollView contentContainerStyle={styles.scrollViewContent}>
<FlmText style={styles.heading}>
๋ฐฐ๋ ์จ๊น/์คํ ํ ๊ธ ์์ (๋ซ๊ธฐ ๋ฒํผ & ์ ๋๋ฉ์ด์
)
</FlmText>
<FlmText style={styles.heading}>
Banner Hide/Open Toggle Example (Close Button & Animation)
</FlmText>
{/* ํ
์คํธ ๋ฐฐ๋ */}
<FlmBanner
type="text"
data={{
message: "ํ
์คํธ๋ฐฐ๋ (์ ๋๋ฉ์ด์
์ ์ฉ)/Text Banner (Animated)",
id: "promo1",
}}
onPress={() =>
Alert.alert(
"ํ
์คํธ ๋ฐฐ๋/Text Banner",
"ํ
์คํธ ๋ฐฐ๋๊ฐ ํด๋ฆญ๋์์ต๋๋ค/Text banner clicked",
)
}
isVisible={isTextBannerVisible} // ๊ฐ๋ณ isVisible prop ์ ๋ฌ / Passing individual isVisible props
onClose={handleCloseTextBanner} // ๋ซ๊ธฐ ์ฝ๋ฐฑ ํจ์ ์ ๋ฌ / Passing a close callback function
animationMaxHeight={80}
style={{
backgroundColor: "#e0f7fa",
borderColor: "#00bcd4",
borderWidth: 1,
}}
textStyle={{ color: "#006064", fontSize: 17 }}
/>
<View style={{ height: 20 }} />
{/* ์ด๋ฏธ์ง ๋ฐฐ๋ 1 */}
<FlmBanner
type="image"
data={{
imageUrl: "https://picsum.photos/600/400",
title:
"์ด๋ฏธ์ง๋ฐฐ๋ 1! (์ ๋๋ฉ์ด์
์ ์ฉ)/Image Banner 1! (Animation applied)",
id: "product2",
}}
onPress={() =>
Alert.alert(
"์ด๋ฏธ์ง ๋ฐฐ๋ 1/Image Banner 1",
"์ด๋ฏธ์ง ๋ฐฐ๋ 1์ด ํด๋ฆญ๋์์ต๋๋ค!/Image banner 1 has been clicked!",
)
}
isVisible={isImageBanner1Visible} // ๊ฐ๋ณ isVisible prop ์ ๋ฌ
onClose={handleCloseImageBanner1} // ๋ซ๊ธฐ ์ฝ๋ฐฑ ํจ์ ์ ๋ฌ
style={{ borderColor: "#ffeb3b", borderWidth: 2 }}
imageStyle={{ borderRadius: 15 }}
titleStyle={{ color: "#4a148c", fontSize: 20, textShadowRadius: 8 }}
/>
<View style={{ height: 20 }} />
{/* ์ด๋ฏธ์ง ์ปค์คํ
๋ฐฐ๋ 2 / Image Custom Banner 2*/}
<FlmBanner
type="image"
data={{
imageUrl:
"https://avatars3.githubusercontent.com/u/17571969?s=400&v=4",
title:
"์ปค์คํ
๋ฐฐ๋ 2! (์ ๋๋ฉ์ด์
์ ์ฉ) / Custom Banner 2! (Animated)",
id: "product3",
}}
onPress={() =>
Alert.alert(
"์ด๋ฏธ์ง ๋ฐฐ๋ 2 / Image Banner 2",
"์ด๋ฏธ์ง ๋ฐฐ๋ 2๊ฐ ํด๋ฆญ๋์์ต๋๋ค! / Image banner 2 was clicked!",
)
}
isVisible={isImageBanner2Visible} // ๊ฐ๋ณ isVisible prop ์ ๋ฌ / Passing individual isVisible props
onClose={handleCloseImageBanner2} // ๋ซ๊ธฐ ์ฝ๋ฐฑ ํจ์ ์ ๋ฌ / Passing a close callback function
style={{ backgroundColor: "#f3e5f5", borderRadius: 20 }}
imageStyle={{ opacity: 0.9 }}
titleStyle={{ color: "#4a148c", fontSize: 22, fontWeight: "normal" }}
/>
<View style={{ height: 30 }} />
{/* ๋ชจ๋ ๋ฐฐ๋๋ฅผ ๋์์ ํ ๊ธํ๋ ๋ฒํผ / Button to toggle all banners simultaneously */}
<FlmButton
title={
isTextBannerVisible ||
isImageBanner1Visible ||
isImageBanner2Visible
? "๋ชจ๋ ๋ฐฐ๋ ์จ๊ธฐ๊ธฐ / Hide all banners"
: "๋ชจ๋ ๋ฐฐ๋ ๋ณด์ด๊ธฐ / Show all banners"
}
onPress={handleToggleAllBanners}
/>
<View style={{ height: 50 }} />
<Text style={styles.content}>
์ฌ๊ธฐ๋ ๋ฐฐ๋ ์๋์ ๋ค๋ฅธ ์ฝํ
์ธ ์
๋๋ค. ๋ฐฐ๋๊ฐ ์ ๋๋ฉ์ด์
๊ณผ ํจ๊ป
์ฌ๋ผ์ง๊ฑฐ๋ ๋ํ๋ ๊ฒ์
๋๋ค.
</Text>
<Text style={styles.content}>
Here is another content below the banner. The banner will disappear or
appear with animation.
</Text>
</ScrollView>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
},
scrollViewContent: {
paddingVertical: 20,
alignItems: "center",
},
heading: {
fontSize: 24,
fontWeight: "bold",
marginBottom: 30,
textAlign: "center",
},
content: {
fontSize: 16,
textAlign: "center",
marginHorizontal: 20,
lineHeight: 24,
},
});
export default FlmBannerApp;
4.์คํฌ๋ฆฐ์ท / ScreenShot