react-native-webview는 안드로이드에서 NestingScroll API를 준수하지 않기 때문에, ScrollView 중첩과 마찬가지로 ScrollView 안에 WebView를 랜더링하면 스크롤이 잘 작동하지 않습니다.
이 경우 WebView의 높이를 컨텐츠 높이까지 늘려서 사용했는데, WebView의 높이가 너무 길어지면 앱이 꺼지거나 스크롤이 튀기는 현상이 발생했었습니다.
그리고 웹뷰도 브라우저이기 때문에, 컴포지터 스래드에서 뷰 너비에 맞는 부분만 가져와 표시하는 최적화가 적용되어 있을텐데, 모든 컨텐츠를 표시하면 리소스도 많이 잡아먹을 것 같습니다.
이 경우 NestedScrollWebView를 사용할 수 있습니다.
패치만 수행하는 라이브러리고, react-native-webview를 그대로 사용하면 됩니다.
react-native-webview는 'RNCWebView' 문자열로 네이티브 모듈에 접근합니다.
import { requireNativeComponent } from "react-native";
import type { NativeWebViewAndroid } from "./WebViewTypes";
const RNCWebView: typeof NativeWebViewAndroid = requireNativeComponent(
'RNCWebView',
);
export default RNCWebView;
nested-scroll-webview는 react-native-webivew에서 정의한 RNCWebView에 해당하는 ViewManager 대신사용할 ViewManager 정의합니다.
package com.reactnativecommunity.webview; // react-native-webview와 동일한 패키지
import static com.reactnativecommunity.webview.RNCWebViewManager.REACT_CLASS;
import com.facebook.react.module.annotations.ReactModule;
import com.facebook.react.uimanager.ThemedReactContext;
@ReactModule(name = REACT_CLASS) // RNCWebView 모듈을 덮어씌운다.
public class RNCNestedScrollWebViewManager extends RNCWebViewManager { // 기존 ViewManager 그대로 이용
@Override
protected RNCWebView createRNCWebViewInstance(ThemedReactContext reactContext) {
return new RNCNestedScrollWebView(reactContext); // 수정된 View 객체 사용
}
@Override
public boolean canOverrideExistingModule() {
return true;
}
}
react-native-webview가 12 버전부터 안드로이드 부분이 많이 바뀌어서 11버전까지만 지원됩니다.
일단 아래와 같이 작동시킬 수는 있는데, 정석대로 하려면 WebViewManager 클래스를 새로 만들어야 합니다.
문제가 되는 부분까지 보여드리기 위해 기존 코드를 수정하는 방법으로 알려드리겠습니다.
1. react-native-webview 수정
RNCWebViewManagerImpl 기능을 상속하여 그대로 사용하기 위해 막혀있는 접근 제한자를 풀어줍니다.
12버전에서 새로 추가된 구현 클래스는 코틀린으로 만들어졌는데, 코틀린의 클래스는 기본적으로 final이기 때문에, 이 부분을 풀어줍니다.
RNCWebViewManagerImpl.kt
open class RNCWebViewManagerImpl {
// ...
open fun createRNCWebViewInstance(context: ThemedReactContext): RNCWebView {
return RNCWebView(context)
}
// ...
}
RNCWebViewManager를 상속하여 덮어씌울 ViewManager가 RNCWebViewManagerImpl 상속 객체를 사용할 수 있도록 private에서 public으로 풀어줍니다.
RNCWebViewManager.java
public class RNCWebViewManager extends ViewGroupManager<RNCWebViewWrapper> {
protected RNCWebViewManagerImpl mRNCWebViewManagerImpl;
}
2. nested-scroll-webview 수정
RNCWebViewManagerImpl.java 생성
package com.reactnativecommunity.webview;
import com.facebook.react.module.annotations.ReactModule;
import com.facebook.react.uimanager.ThemedReactContext;
public class RNCNestedScrollWebViewManagerImpl extends RNCWebViewManagerImpl {
@Override
public RNCWebView createRNCWebViewInstance(ThemedReactContext reactContext) {
return new RNCNestedScrollWebView(reactContext);
}
}
RNCWebViewManager.java 수정
package com.reactnativecommunity.webview;
import com.facebook.react.module.annotations.ReactModule;
import com.facebook.react.uimanager.ThemedReactContext;
@ReactModule(name = RNCWebViewManagerImpl.NAME) // "RNCWebView"
public class RNCNestedScrollWebViewManager extends RNCWebViewManager {
public RNCNestedScrollWebViewManager() {
mRNCWebViewManagerImpl = new RNCNestedScrollWebViewManagerImpl();
}
@Override
public RNCWebViewWrapper createViewInstance(ThemedReactContext reactContext) {
return mRNCWebViewManagerImpl.createViewInstance(reactContext);
}
}
RNCWebView는 RNCWebViewManager의 중첩 클래스에서 독립했습니다.
RNCNestedScrollWebView.java 수정
public class RNCNestedScrollWebView extends RNCWebViewManager.RNCWebView implements NestedScrollingChild3 {
// ...
}
3. 프로젝트 수정
MainApplication.kt 경로에 NestedWebViewPackage.java 생성
package com.myapp; // 수정
import androidx.annotation.NonNull;
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;
import com.reactnativecommunity.webview.RNCNestedScrollWebViewManager;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class NestedWebViewPackage implements ReactPackage {
@NonNull
@Override
public List<NativeModule> createNativeModules(@NonNull ReactApplicationContext reactContext) {
return Collections.emptyList();
}
@NonNull
@Override
public List<ViewManager> createViewManagers(@NonNull ReactApplicationContext reactContext) {
return Arrays.asList(
new RNCNestedScrollWebViewManager()
);
}
}
MainApplication.kt 수정
package com.myapp
class MainApplication : Application(), ReactApplication {
override val reactNativeHost: ReactNativeHost =
object : DefaultReactNativeHost(this) {
override fun getPackages(): List<ReactPackage> =
PackageList(this).packages.apply {
add(NestedWebViewPackage()) // 추가
}
// ...
}
}
'리액트 네이티브' 카테고리의 다른 글
flash-list로 복잡한 레이아웃 구현하기 (0) | 2024.10.16 |
---|---|
리액트 네이티브에서 IntersectionObserver를 대체하는 방법 (0) | 2024.10.16 |
리액트 네이티브 스크롤뷰 중첩 (0) | 2024.10.03 |
리액트 네이티브가 느린 이유 (0) | 2024.08.27 |
리액트 네이티브 터치 이벤트 흐름 (0) | 2024.08.27 |