react-native에서 blur 효과를 주고싶은경우
https://github.com/Kureev/react-native-blur
라이브러리를 사용하는 방법도 있지만 해당 라이브러리는 베이스컬러지정을 못하거나
특정 OS, 특정 기기에서 과부하 이슈가 있는것을 확인하였으며 UI부분의 대한 이슈도 많기에 웹뷰로 구현하는 방식을 채택했습니다.
원본) https://gist.github.com/dutradotdev/50c82763fc621ab3c1bd5ba02180ce0d
react-native 0.64.0
react-native-webview 11.13.0
npm install react-native-webview
import React from "react";
import { ColorValue, InteractionManager, StyleSheet, View } from "react-native";
import WebView from "react-native-webview";
export interface BlurViewProps {
/**
* @example rgba(0, 0, 0, 0.5)
* @default "rgba(255, 255, 255, 0.8)"
*/
backgroundColor?: ColorValue;
/**
* - px 단위
* @default 10
*/
blurRadius?: number;
}
const BlurView: React.VFC<BlurViewProps> = ({ backgroundColor, blurRadius }) => {
return (
<View
style={[
StyleSheet.absoluteFill,
{
backgroundColor: "#00000000",
overflow: "hidden"
}
]}
>
<WebView
style={{
width: "100%",
height: "100%",
backgroundColor: "#00000000"
}}
originWhitelist={["*"]}
overScrollMode='never'
scrollEnabled={false}
source={{
html: `
<html>
<head>
<meta name="viewport" content="initial-scale=1.0 maximum-scale=1.0" />
<style>
.blur {
position: absolute;
top: 0;
right:0;
bottom: 0;
left: 0;
background: ${String(backgroundColor)};
-webkit-backdrop-filter: blur(${blurRadius}px);
backdrop-filter: blur(${blurRadius}px);
}
</style>
</head>
<body>
<div class="blur" />
</body>
</html>
`
}}
/>
</View>
);
};
BlurView.defaultProps = {
backgroundColor: "rgba(255, 255, 255, 0.8)",
blurRadius: 10
};
export default BlurView;
해당 코드는 Android13에서 이슈가 발생했습니다.
BlurView에 크기가 작은경우 webview내부의 blur css가 적용되지않았습니다.
import React from "react";
import { ColorValue, Dimensions, InteractionManager, StyleSheet, View } from "react-native";
import WebView from "react-native-webview";
export interface BlurViewProps {
/**
* @example rgba(0, 0, 0, 0.5)
* @default "rgba(255, 255, 255, 0.8)"
*/
backgroundColor?: ColorValue;
/**
* - px 단위
* @default 10
*/
blurRadius?: number;
}
const BlurView: React.VFC<BlurViewProps> = ({ backgroundColor, blurRadius }) => {
return (
<View
style={[
StyleSheet.absoluteFill,
{
backgroundColor: "#00000000",
overflow: "hidden"
}
]}
>
<WebView
style={{
width: "100%",
height: "100%",
backgroundColor: "#00000000"
}}
originWhitelist={["*"]}
overScrollMode='never'
scrollEnabled={false}
source={{
html: `
<html>
<head>
<meta name="viewport" content="initial-scale=1.0 maximum-scale=1.0" />
<style>
.blur {
position: absolute;
top: 0;
right:0;
bottom: 0;
left: 0;
height: ${Dimensions.get("screen").height}px;
background: ${String(backgroundColor)};
-webkit-backdrop-filter: blur(${blurRadius}px);
backdrop-filter: blur(${blurRadius}px);
}
</style>
</head>
<body>
<div class="blur" />
</body>
</html>
`
}}
/>
</View>
);
};
BlurView.defaultProps = {
backgroundColor: "rgba(255, 255, 255, 0.8)",
blurRadius: 10
};
export default BlurView;
<style>
.blur {
position: absolute;
top: 0;
right:0;
bottom: 0;
left: 0;
height: ${Dimensions.get("screen").height}px;
background: ${String(backgroundColor)};
-webkit-backdrop-filter: blur(${blurRadius}px);
backdrop-filter: blur(${blurRadius}px);
}
</style>
내용은 거의 동일하지만 height에 강제적으로 현재 디바이스 크기를 할당하여 내부컨텐츠를 늘려서 해결했습니다. 해결은 하였지만 너무 마음에 안드네요 혹시나 다른 해결방법이 있다면 공유해주시면 정말 감사하겠습니다.
const App = () => {
return (
<SafeAreaView style={{ flex: 1, backgroundColor: "#FFF" }}>
<View style={{ flex: 1, backgroundColor: "#FFF" }}>
<View style={{ flex: 1, position: "relative" }}>
<Image
source={{
uri: "https://upload.wikimedia.org/wikipedia/commons/thumb/a/a7/React-icon.svg/1200px-React-icon.svg.png"
}}
style={{ flex: 1 }}
resizeMode='contain'
/>
<BlurView backgroundColor={"rgba(255, 255, 255, 0.4)"} blurRadius={5} />
</View>
<View style={{ height: 30, backgroundColor: "#000" }} />
<View style={{ flex: 1 }}>
<Image
source={{
uri: "https://upload.wikimedia.org/wikipedia/commons/thumb/a/a7/React-icon.svg/1200px-React-icon.svg.png"
}}
style={{ flexGrow: 1 }}
resizeMode='contain'
/>
</View>
</View>
</SafeAreaView>
);
};