react-native-daro 1.0.15 → 1.0.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/android/build.gradle +11 -1
- package/android/src/main/java/com/daro/reactnative/DaroMAdBannerViewManager.kt +34 -11
- package/android/src/main/java/com/daro/reactnative/DaroMAdNativeViewManager.kt +79 -48
- package/android/src/main/java/com/daro/reactnative/DaroMModule.kt +80 -25
- package/android/src/main/java/com/daro/reactnative/DaroMPackage.kt +28 -4
- package/android/src/main/java/com/daro/reactnative/DaroMediaViewManager.kt +25 -0
- package/android/src/main/java/com/daro/reactnative/event/DaroMEvent.kt +18 -7
- package/android/src/main/java/com/daro/reactnative/util/EventEmitterUtil.kt +18 -5
- package/android/src/main/java/com/daro/reactnative/view/DaroMAdNativeViewContainer.kt +301 -52
- package/android/src/main/java/com/daro/reactnative/view/DaroMediaView.kt +123 -0
- package/android/src/newarch/java/com/daro/reactnative/DaroMModuleSpec.kt +6 -0
- package/android/src/oldarch/java/com/daro/reactnative/DaroMModuleSpec.kt +90 -0
- package/ios/DaroMModule+AppOpen.swift +13 -10
- package/ios/DaroMModule+Interstitial.swift +12 -9
- package/ios/DaroMModule+LightPopup.swift +16 -13
- package/ios/DaroMModule+Rewarded.swift +12 -9
- package/ios/DaroMModule.mm +45 -17
- package/ios/DaroMModule.swift +4 -4
- package/ios/Fabric/DaroMAdBannerComponentView.mm +207 -0
- package/ios/Fabric/DaroMFabricEventSink.mm +31 -0
- package/ios/Fabric/DaroMFabricPropApplier.mm +123 -0
- package/ios/Fabric/DaroMNativeAdComponentView.mm +294 -0
- package/ios/{DaroMAdBannerViewManager.m → Paper/DaroMAdBannerViewManager.m} +3 -1
- package/ios/Paper/DaroMAdBannerViewManager.swift +21 -0
- package/ios/{DaroMNativeAdViewManager.m → Paper/DaroMNativeAdViewManager.m} +2 -1
- package/ios/Paper/DaroMNativeAdViewManager.swift +22 -0
- package/ios/Shared/DaroMAdEventSink.swift +24 -0
- package/ios/Shared/DaroMBannerAdView.swift +188 -0
- package/ios/Shared/DaroMNativeAdLoadCoordinator.swift +49 -0
- package/ios/Shared/DaroMNativeAdView.swift +575 -0
- package/ios/Shared/DaroMNativeAssetResolver.swift +53 -0
- package/ios/mediation/admob/DaroMediationTypes.swift +1 -0
- package/lib/commonjs/AdBannerView.js +20 -39
- package/lib/commonjs/AdBannerView.js.map +1 -1
- package/lib/commonjs/AppOpenAd.js +43 -10
- package/lib/commonjs/AppOpenAd.js.map +1 -1
- package/lib/commonjs/DaroMAdBannerViewNativeComponent.ts +47 -0
- package/lib/commonjs/DaroMNativeAdViewNativeComponent.ts +62 -0
- package/lib/commonjs/DaroMediaViewNativeComponent.ts +9 -0
- package/lib/commonjs/EventEmitter.js +4 -5
- package/lib/commonjs/EventEmitter.js.map +1 -1
- package/lib/commonjs/InterstitialAd.js +9 -11
- package/lib/commonjs/InterstitialAd.js.map +1 -1
- package/lib/commonjs/LightPopupAd.js +11 -12
- package/lib/commonjs/LightPopupAd.js.map +1 -1
- package/lib/commonjs/NativeDaroModule.js +9 -0
- package/lib/commonjs/NativeDaroModule.js.map +1 -0
- package/lib/commonjs/RewardedAd.js +9 -11
- package/lib/commonjs/RewardedAd.js.map +1 -1
- package/lib/commonjs/codegen-env.d.js +2 -0
- package/lib/commonjs/codegen-env.d.js.map +1 -0
- package/lib/commonjs/hooks/useInterstitialAd.js +110 -0
- package/lib/commonjs/hooks/useInterstitialAd.js.map +1 -0
- package/lib/commonjs/hooks/useLightPopupAd.js +114 -0
- package/lib/commonjs/hooks/useLightPopupAd.js.map +1 -0
- package/lib/commonjs/hooks/useRewardedAd.js +113 -0
- package/lib/commonjs/hooks/useRewardedAd.js.map +1 -0
- package/lib/commonjs/index.js +29 -13
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/nativeAd/NativeAdView.js +23 -22
- package/lib/commonjs/nativeAd/NativeAdView.js.map +1 -1
- package/lib/commonjs/nativeAd/NativeAdViewComponents.js +43 -31
- package/lib/commonjs/nativeAd/NativeAdViewComponents.js.map +1 -1
- package/lib/commonjs/nativeAd/NativeAdViewProvider.js +34 -7
- package/lib/commonjs/nativeAd/NativeAdViewProvider.js.map +1 -1
- package/lib/module/AdBannerView.js +19 -40
- package/lib/module/AdBannerView.js.map +1 -1
- package/lib/module/AppOpenAd.js +43 -11
- package/lib/module/AppOpenAd.js.map +1 -1
- package/lib/module/DaroMAdBannerViewNativeComponent.ts +47 -0
- package/lib/module/DaroMNativeAdViewNativeComponent.ts +62 -0
- package/lib/module/DaroMediaViewNativeComponent.ts +9 -0
- package/lib/module/EventEmitter.js +4 -6
- package/lib/module/EventEmitter.js.map +1 -1
- package/lib/module/InterstitialAd.js +8 -11
- package/lib/module/InterstitialAd.js.map +1 -1
- package/lib/module/LightPopupAd.js +11 -13
- package/lib/module/LightPopupAd.js.map +1 -1
- package/lib/module/NativeDaroModule.js +5 -0
- package/lib/module/NativeDaroModule.js.map +1 -0
- package/lib/module/RewardedAd.js +8 -11
- package/lib/module/RewardedAd.js.map +1 -1
- package/lib/module/codegen-env.d.js +2 -0
- package/lib/module/codegen-env.d.js.map +1 -0
- package/lib/module/hooks/useInterstitialAd.js +106 -0
- package/lib/module/hooks/useInterstitialAd.js.map +1 -0
- package/lib/module/hooks/useLightPopupAd.js +110 -0
- package/lib/module/hooks/useLightPopupAd.js.map +1 -0
- package/lib/module/hooks/useRewardedAd.js +109 -0
- package/lib/module/hooks/useRewardedAd.js.map +1 -0
- package/lib/module/index.js +7 -13
- package/lib/module/index.js.map +1 -1
- package/lib/module/nativeAd/NativeAdView.js +22 -23
- package/lib/module/nativeAd/NativeAdView.js.map +1 -1
- package/lib/module/nativeAd/NativeAdViewComponents.js +45 -34
- package/lib/module/nativeAd/NativeAdViewComponents.js.map +1 -1
- package/lib/module/nativeAd/NativeAdViewProvider.js +35 -8
- package/lib/module/nativeAd/NativeAdViewProvider.js.map +1 -1
- package/lib/typescript/commonjs/plugin/src/index.d.ts +1 -1
- package/lib/typescript/commonjs/plugin/src/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/plugin/src/withAndroid.d.ts.map +1 -1
- package/lib/typescript/commonjs/plugin/src/withIos.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/AdBannerView.d.ts +2 -2
- package/lib/typescript/commonjs/src/AdBannerView.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/AppOpenAd.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/DaroMAdBannerViewNativeComponent.d.ts +32 -0
- package/lib/typescript/commonjs/src/DaroMAdBannerViewNativeComponent.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/DaroMNativeAdViewNativeComponent.d.ts +42 -0
- package/lib/typescript/commonjs/src/DaroMNativeAdViewNativeComponent.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/DaroMediaViewNativeComponent.d.ts +6 -0
- package/lib/typescript/commonjs/src/DaroMediaViewNativeComponent.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/EventEmitter.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/InterstitialAd.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/LightPopupAd.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/NativeDaroModule.d.ts +61 -0
- package/lib/typescript/commonjs/src/NativeDaroModule.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/RewardedAd.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/hooks/useInterstitialAd.d.ts +19 -0
- package/lib/typescript/commonjs/src/hooks/useInterstitialAd.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/hooks/useLightPopupAd.d.ts +23 -0
- package/lib/typescript/commonjs/src/hooks/useLightPopupAd.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/hooks/useRewardedAd.d.ts +20 -0
- package/lib/typescript/commonjs/src/hooks/useRewardedAd.d.ts.map +1 -0
- package/lib/typescript/commonjs/src/index.d.ts +7 -1
- package/lib/typescript/commonjs/src/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/nativeAd/NativeAdView.d.ts +1 -0
- package/lib/typescript/commonjs/src/nativeAd/NativeAdView.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/nativeAd/NativeAdViewComponents.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/nativeAd/NativeAdViewProvider.d.ts +11 -5
- package/lib/typescript/commonjs/src/nativeAd/NativeAdViewProvider.d.ts.map +1 -1
- package/lib/typescript/commonjs/src/types/NativeAdViewProps.d.ts +2 -0
- package/lib/typescript/commonjs/src/types/NativeAdViewProps.d.ts.map +1 -1
- package/lib/typescript/module/plugin/src/index.d.ts +1 -1
- package/lib/typescript/module/plugin/src/index.d.ts.map +1 -1
- package/lib/typescript/module/plugin/src/withAndroid.d.ts.map +1 -1
- package/lib/typescript/module/plugin/src/withIos.d.ts.map +1 -1
- package/lib/typescript/module/src/AdBannerView.d.ts +2 -2
- package/lib/typescript/module/src/AdBannerView.d.ts.map +1 -1
- package/lib/typescript/module/src/AppOpenAd.d.ts.map +1 -1
- package/lib/typescript/module/src/DaroMAdBannerViewNativeComponent.d.ts +32 -0
- package/lib/typescript/module/src/DaroMAdBannerViewNativeComponent.d.ts.map +1 -0
- package/lib/typescript/module/src/DaroMNativeAdViewNativeComponent.d.ts +42 -0
- package/lib/typescript/module/src/DaroMNativeAdViewNativeComponent.d.ts.map +1 -0
- package/lib/typescript/module/src/DaroMediaViewNativeComponent.d.ts +6 -0
- package/lib/typescript/module/src/DaroMediaViewNativeComponent.d.ts.map +1 -0
- package/lib/typescript/module/src/EventEmitter.d.ts.map +1 -1
- package/lib/typescript/module/src/InterstitialAd.d.ts.map +1 -1
- package/lib/typescript/module/src/LightPopupAd.d.ts.map +1 -1
- package/lib/typescript/module/src/NativeDaroModule.d.ts +61 -0
- package/lib/typescript/module/src/NativeDaroModule.d.ts.map +1 -0
- package/lib/typescript/module/src/RewardedAd.d.ts.map +1 -1
- package/lib/typescript/module/src/hooks/useInterstitialAd.d.ts +19 -0
- package/lib/typescript/module/src/hooks/useInterstitialAd.d.ts.map +1 -0
- package/lib/typescript/module/src/hooks/useLightPopupAd.d.ts +23 -0
- package/lib/typescript/module/src/hooks/useLightPopupAd.d.ts.map +1 -0
- package/lib/typescript/module/src/hooks/useRewardedAd.d.ts +20 -0
- package/lib/typescript/module/src/hooks/useRewardedAd.d.ts.map +1 -0
- package/lib/typescript/module/src/index.d.ts +7 -1
- package/lib/typescript/module/src/index.d.ts.map +1 -1
- package/lib/typescript/module/src/nativeAd/NativeAdView.d.ts +1 -0
- package/lib/typescript/module/src/nativeAd/NativeAdView.d.ts.map +1 -1
- package/lib/typescript/module/src/nativeAd/NativeAdViewComponents.d.ts.map +1 -1
- package/lib/typescript/module/src/nativeAd/NativeAdViewProvider.d.ts +11 -5
- package/lib/typescript/module/src/nativeAd/NativeAdViewProvider.d.ts.map +1 -1
- package/lib/typescript/module/src/types/NativeAdViewProps.d.ts +2 -0
- package/lib/typescript/module/src/types/NativeAdViewProps.d.ts.map +1 -1
- package/package.json +12 -5
- package/plugin/build/index.d.ts +1 -1
- package/plugin/build/withAndroid.js +99 -17
- package/plugin/build/withIos.js +4 -5
- package/react-native-daro.podspec +3 -0
- package/src/AdBannerView.tsx +24 -61
- package/src/AppOpenAd.ts +46 -9
- package/src/DaroMAdBannerViewNativeComponent.ts +47 -0
- package/src/DaroMNativeAdViewNativeComponent.ts +62 -0
- package/src/DaroMediaViewNativeComponent.ts +9 -0
- package/src/EventEmitter.ts +4 -5
- package/src/InterstitialAd.ts +8 -10
- package/src/LightPopupAd.ts +11 -12
- package/src/NativeDaroModule.ts +91 -0
- package/src/RewardedAd.ts +8 -10
- package/src/codegen-env.d.ts +45 -0
- package/src/hooks/useInterstitialAd.ts +117 -0
- package/src/hooks/useLightPopupAd.ts +132 -0
- package/src/hooks/useRewardedAd.ts +122 -0
- package/src/index.tsx +21 -22
- package/src/nativeAd/NativeAdView.tsx +41 -54
- package/src/nativeAd/NativeAdViewComponents.tsx +80 -42
- package/src/nativeAd/NativeAdViewProvider.tsx +75 -17
- package/src/types/NativeAdViewProps.ts +7 -0
- package/ios/DaroMAdBannerViewManager.swift +0 -91
- package/ios/DaroMNativeAdViewManager.swift +0 -291
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
package com.daro.reactnative.util
|
|
2
2
|
|
|
3
3
|
import android.view.View
|
|
4
|
+
import com.daro.reactnative.event.AdViewEvent
|
|
4
5
|
import com.daro.reactnative.event.DaroMEvent
|
|
5
6
|
import com.facebook.react.bridge.ReactContext
|
|
6
7
|
import com.facebook.react.bridge.WritableMap
|
|
7
8
|
import com.facebook.react.modules.core.DeviceEventManagerModule
|
|
8
|
-
import com.facebook.react.uimanager.
|
|
9
|
+
import com.facebook.react.uimanager.UIManagerHelper
|
|
10
|
+
import com.facebook.react.uimanager.events.Event
|
|
9
11
|
|
|
10
12
|
internal object EventEmitterUtil {
|
|
11
13
|
// React Native Bridge
|
|
@@ -15,10 +17,21 @@ internal object EventEmitterUtil {
|
|
|
15
17
|
.emit(event.value, params)
|
|
16
18
|
}
|
|
17
19
|
|
|
18
|
-
fun View.sendNativeViewEvent(reactContext: ReactContext, event:
|
|
19
|
-
reactContext
|
|
20
|
-
|
|
21
|
-
.
|
|
20
|
+
fun View.sendNativeViewEvent(reactContext: ReactContext, event: AdViewEvent, params: WritableMap?) {
|
|
21
|
+
val eventDispatcher = UIManagerHelper.getEventDispatcherForReactTag(reactContext, id) ?: return
|
|
22
|
+
eventDispatcher.dispatchEvent(
|
|
23
|
+
AdViewDispatchedEvent(UIManagerHelper.getSurfaceId(reactContext), id, event, params)
|
|
24
|
+
)
|
|
22
25
|
}
|
|
23
26
|
}
|
|
24
27
|
|
|
28
|
+
private class AdViewDispatchedEvent(
|
|
29
|
+
surfaceId: Int,
|
|
30
|
+
viewId: Int,
|
|
31
|
+
private val event: AdViewEvent,
|
|
32
|
+
private val payload: WritableMap?,
|
|
33
|
+
) : Event<AdViewDispatchedEvent>(surfaceId, viewId) {
|
|
34
|
+
override fun getEventName() = event.value
|
|
35
|
+
|
|
36
|
+
override fun getEventData() = payload
|
|
37
|
+
}
|
|
@@ -7,7 +7,9 @@ import android.text.SpannableString
|
|
|
7
7
|
import android.text.Spanned
|
|
8
8
|
import android.view.View
|
|
9
9
|
import android.view.ViewGroup
|
|
10
|
+
import android.widget.FrameLayout
|
|
10
11
|
import android.widget.ImageView
|
|
12
|
+
import android.widget.TextView
|
|
11
13
|
import androidx.annotation.IdRes
|
|
12
14
|
import androidx.core.view.children
|
|
13
15
|
import com.daro.reactnative.event.AdViewEvent
|
|
@@ -20,6 +22,7 @@ import droom.daro.core.adunit.DaroNativeAdUnit
|
|
|
20
22
|
import droom.daro.core.model.DaroAdInfo
|
|
21
23
|
import droom.daro.core.model.DaroAdLoadError
|
|
22
24
|
import droom.daro.core.model.DaroNativeAdBinder
|
|
25
|
+
import droom.daro.core.model.DaroNativeAdChoicePlacement
|
|
23
26
|
import droom.daro.core.model.DaroViewAd
|
|
24
27
|
import droom.daro.view.DaroAdViewListener
|
|
25
28
|
import droom.daro.view.DaroNativeAdView
|
|
@@ -31,6 +34,11 @@ import kotlin.math.roundToInt
|
|
|
31
34
|
class DaroMAdNativeViewContainer(val context: ReactContext) : ReactViewGroup(context),
|
|
32
35
|
DaroAdViewListener {
|
|
33
36
|
|
|
37
|
+
private companion object {
|
|
38
|
+
private const val MAX_LOAD_ASSET_VIEW_RETRY_COUNT = 40
|
|
39
|
+
private const val LOAD_ASSET_VIEW_RETRY_DELAY_MS = 50L
|
|
40
|
+
}
|
|
41
|
+
|
|
34
42
|
private val adViewContainer: ReactViewGroup = ReactViewGroup(context)
|
|
35
43
|
|
|
36
44
|
init {
|
|
@@ -46,24 +54,75 @@ class DaroMAdNativeViewContainer(val context: ReactContext) : ReactViewGroup(con
|
|
|
46
54
|
internal var adUnitId: String = ""
|
|
47
55
|
|
|
48
56
|
internal var loadOnMount: Boolean = true
|
|
57
|
+
private var adChoicesPosition: DaroNativeAdChoicePlacement =
|
|
58
|
+
DaroNativeAdChoicePlacement.BOTTOM_RIGHT
|
|
49
59
|
|
|
50
60
|
private var isFirstLoad: Boolean = true
|
|
61
|
+
private var isDestroyed: Boolean = false
|
|
62
|
+
private var pendingLoadAssetViewRetryCount: Int = 0
|
|
51
63
|
|
|
52
|
-
fun
|
|
53
|
-
|
|
64
|
+
fun addReactSubview(child: View, index: Int) {
|
|
65
|
+
if (isDestroyed) return
|
|
54
66
|
|
|
55
|
-
|
|
67
|
+
if (index < 0 || index >= adViewContainer.childCount) {
|
|
68
|
+
adViewContainer.addView(child)
|
|
69
|
+
} else {
|
|
70
|
+
adViewContainer.addView(child, index)
|
|
71
|
+
}
|
|
56
72
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
}
|
|
73
|
+
scheduleInitialLoadIfNeeded()
|
|
74
|
+
}
|
|
60
75
|
|
|
61
|
-
|
|
62
|
-
|
|
76
|
+
fun getReactSubviewCount(): Int {
|
|
77
|
+
if (isDestroyed) return 0
|
|
78
|
+
|
|
79
|
+
return adViewContainer.childCount
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
fun getReactSubviewAt(index: Int): View {
|
|
83
|
+
return adViewContainer.getChildAt(index)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
fun removeReactSubviewAt(index: Int) {
|
|
87
|
+
if (isDestroyed || index < 0 || index >= adViewContainer.childCount) return
|
|
88
|
+
|
|
89
|
+
adViewContainer.removeViewAt(index)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
fun removeAllReactSubviews() {
|
|
93
|
+
if (isDestroyed) return
|
|
94
|
+
|
|
95
|
+
adViewContainer.removeAllViews()
|
|
63
96
|
}
|
|
64
97
|
|
|
65
|
-
|
|
66
|
-
if(
|
|
98
|
+
fun loadAd(): Boolean {
|
|
99
|
+
if (isDestroyed) return false
|
|
100
|
+
|
|
101
|
+
if (!hasRegisteredAssetView()) {
|
|
102
|
+
scheduleLoadWhenAssetViewsMounted()
|
|
103
|
+
return false
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (!areRegisteredAssetViewsMounted()) {
|
|
107
|
+
scheduleLoadWhenAssetViewsMounted()
|
|
108
|
+
return false
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
pendingLoadAssetViewRetryCount = 0
|
|
112
|
+
captureRegisteredTextSpans()
|
|
113
|
+
|
|
114
|
+
return (adView ?: buildAdView())?.let { view ->
|
|
115
|
+
|
|
116
|
+
adView = view
|
|
117
|
+
|
|
118
|
+
if (view.parent == null) {
|
|
119
|
+
this@DaroMAdNativeViewContainer.addView(view)
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
view.loadAd()
|
|
123
|
+
isFirstLoad = false
|
|
124
|
+
true
|
|
125
|
+
} ?: false
|
|
67
126
|
}
|
|
68
127
|
|
|
69
128
|
private fun buildAdView(): DaroNativeAdView? {
|
|
@@ -84,8 +143,13 @@ class DaroMAdNativeViewContainer(val context: ReactContext) : ReactViewGroup(con
|
|
|
84
143
|
.let { if (titleViewId != null) it.setTitleViewId(titleViewId!!) else it }
|
|
85
144
|
.let { if (bodyViewId != null) it.setBodyTextViewId(bodyViewId!!) else it }
|
|
86
145
|
.let { if (iconViewId != null) it.setIconViewId(iconViewId!!) else it }
|
|
87
|
-
.let {
|
|
146
|
+
.let { builder ->
|
|
147
|
+
// 등록 누락 시 더미 뷰에 바인딩되지 않도록 DaroMediaView를 직접 찾아 폴백한다.
|
|
148
|
+
val mediaId = mediaViewId ?: findDaroMediaViewId()
|
|
149
|
+
if (mediaId != null) builder.setMediaViewGroupId(mediaId) else builder
|
|
150
|
+
}
|
|
88
151
|
.let { if (callToActionViewId != null) it.setCallToActionViewId(callToActionViewId!!) else it }
|
|
152
|
+
.setAdChoicePlacement(adChoicesPosition)
|
|
89
153
|
.build()
|
|
90
154
|
)
|
|
91
155
|
|
|
@@ -109,13 +173,34 @@ class DaroMAdNativeViewContainer(val context: ReactContext) : ReactViewGroup(con
|
|
|
109
173
|
}
|
|
110
174
|
|
|
111
175
|
fun destroy() {
|
|
112
|
-
|
|
176
|
+
isDestroyed = true
|
|
177
|
+
loadAdHandler.removeCallbacksAndMessages(null)
|
|
178
|
+
setOnClickListener(null)
|
|
179
|
+
|
|
180
|
+
adView?.let { view ->
|
|
181
|
+
(view.parent as? ViewGroup)?.removeView(view)
|
|
182
|
+
view.destroy()
|
|
183
|
+
installFallbackAssetViews()
|
|
184
|
+
}
|
|
185
|
+
adView = null
|
|
186
|
+
pendingLoadAssetViewRetryCount = 0
|
|
187
|
+
removeAllViews()
|
|
188
|
+
testSpanMap.clear()
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
override fun onAttachedToWindow() {
|
|
192
|
+
super.onAttachedToWindow()
|
|
193
|
+
if (!isDestroyed) {
|
|
194
|
+
adView?.resume()
|
|
195
|
+
}
|
|
113
196
|
}
|
|
114
197
|
|
|
115
198
|
override fun onAdLoadSuccess(
|
|
116
199
|
ad: DaroViewAd,
|
|
117
200
|
adInfo: DaroAdInfo,
|
|
118
201
|
) {
|
|
202
|
+
if (isDestroyed) return
|
|
203
|
+
|
|
119
204
|
sendNativeViewEvent(
|
|
120
205
|
reactContext = context,
|
|
121
206
|
event = AdViewEvent.ON_AD_LOADED,
|
|
@@ -123,6 +208,7 @@ class DaroMAdNativeViewContainer(val context: ReactContext) : ReactViewGroup(con
|
|
|
123
208
|
)
|
|
124
209
|
|
|
125
210
|
post({
|
|
211
|
+
layoutMediaViewChildrenFallback()
|
|
126
212
|
context.currentActivity?.window.let { window ->
|
|
127
213
|
window?.decorView?.requestLayout()
|
|
128
214
|
}
|
|
@@ -130,6 +216,8 @@ class DaroMAdNativeViewContainer(val context: ReactContext) : ReactViewGroup(con
|
|
|
130
216
|
}
|
|
131
217
|
|
|
132
218
|
override fun onAdLoadFail(err: DaroAdLoadError) {
|
|
219
|
+
if (isDestroyed) return
|
|
220
|
+
|
|
133
221
|
sendNativeViewEvent(
|
|
134
222
|
reactContext = context,
|
|
135
223
|
event = AdViewEvent.ON_AD_FAILED_TO_LOAD,
|
|
@@ -138,6 +226,8 @@ class DaroMAdNativeViewContainer(val context: ReactContext) : ReactViewGroup(con
|
|
|
138
226
|
}
|
|
139
227
|
|
|
140
228
|
override fun onAdClicked(adInfo: DaroAdInfo) {
|
|
229
|
+
if (isDestroyed) return
|
|
230
|
+
|
|
141
231
|
sendNativeViewEvent(
|
|
142
232
|
reactContext = context,
|
|
143
233
|
event = AdViewEvent.ON_AD_CLICKED,
|
|
@@ -146,6 +236,8 @@ class DaroMAdNativeViewContainer(val context: ReactContext) : ReactViewGroup(con
|
|
|
146
236
|
}
|
|
147
237
|
|
|
148
238
|
override fun onAdImpression(adInfo: DaroAdInfo) {
|
|
239
|
+
if (isDestroyed) return
|
|
240
|
+
|
|
149
241
|
sendNativeViewEvent(
|
|
150
242
|
reactContext = context,
|
|
151
243
|
event = AdViewEvent.ON_AD_IMPRESSION,
|
|
@@ -155,19 +247,30 @@ class DaroMAdNativeViewContainer(val context: ReactContext) : ReactViewGroup(con
|
|
|
155
247
|
|
|
156
248
|
private val loadAdHandler = Handler(Looper.getMainLooper())
|
|
157
249
|
private val loadAdTask = LoadAdTask(this)
|
|
250
|
+
private val retryLoadAdTask = Runnable {
|
|
251
|
+
if (!isDestroyed) {
|
|
252
|
+
loadAd()
|
|
253
|
+
}
|
|
254
|
+
}
|
|
158
255
|
|
|
159
256
|
private inner class LoadAdTask(private val nativeAdView: DaroMAdNativeViewContainer) :
|
|
160
257
|
Runnable {
|
|
161
258
|
|
|
162
259
|
override fun run() {
|
|
163
260
|
nativeAdView.loadAd()
|
|
164
|
-
nativeAdView.isFirstLoad = false
|
|
165
261
|
}
|
|
166
262
|
}
|
|
167
263
|
|
|
168
264
|
internal fun onSetProps() {
|
|
169
|
-
if (
|
|
170
|
-
|
|
265
|
+
if (isDestroyed) return
|
|
266
|
+
|
|
267
|
+
scheduleInitialLoadIfNeeded()
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
private fun scheduleInitialLoadIfNeeded() {
|
|
271
|
+
loadAdHandler.removeCallbacks(loadAdTask)
|
|
272
|
+
|
|
273
|
+
if (loadOnMount && isFirstLoad && adUnitId.isNotEmpty() && hasRegisteredAssetView()) {
|
|
171
274
|
loadAdHandler.postDelayed(loadAdTask, 50)
|
|
172
275
|
}
|
|
173
276
|
}
|
|
@@ -185,7 +288,11 @@ class DaroMAdNativeViewContainer(val context: ReactContext) : ReactViewGroup(con
|
|
|
185
288
|
)
|
|
186
289
|
|
|
187
290
|
adView?.layout(0, 0, width, height)
|
|
291
|
+
} catch (_: Exception) {
|
|
292
|
+
// Ignore
|
|
293
|
+
}
|
|
188
294
|
|
|
295
|
+
try {
|
|
189
296
|
adViewContainer.parent?.let {
|
|
190
297
|
(it as ViewGroup).children.filter { it != adViewContainer && it is ViewGroup }.lastOrNull()
|
|
191
298
|
?.let {
|
|
@@ -199,8 +306,10 @@ class DaroMAdNativeViewContainer(val context: ReactContext) : ReactViewGroup(con
|
|
|
199
306
|
findImageView(it as ViewGroup)?.let { adChoiceImageView ->
|
|
200
307
|
if ((adChoiceImageView.parent as View).measuredWidth == adChoiceImageView.measuredWidth) return@let
|
|
201
308
|
|
|
309
|
+
val adChoiceDrawable = adChoiceImageView.drawable ?: return@let
|
|
310
|
+
|
|
202
311
|
val ratio =
|
|
203
|
-
|
|
312
|
+
adChoiceDrawable.intrinsicHeight.toFloat() / (adChoiceImageView.parent as View).height
|
|
204
313
|
|
|
205
314
|
val w = ((adChoiceImageView.parent as View).width * ratio).roundToInt()
|
|
206
315
|
val h = ((adChoiceImageView.parent as View).height * ratio).roundToInt()
|
|
@@ -223,27 +332,18 @@ class DaroMAdNativeViewContainer(val context: ReactContext) : ReactViewGroup(con
|
|
|
223
332
|
}
|
|
224
333
|
}
|
|
225
334
|
}
|
|
335
|
+
} catch (_: Exception) {
|
|
336
|
+
// Ignore
|
|
337
|
+
}
|
|
226
338
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
child.measure(
|
|
233
|
-
MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
|
|
234
|
-
MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)
|
|
235
|
-
)
|
|
236
|
-
|
|
237
|
-
child.layout(0, 0, width, height)
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
titleViewId?.let { adViewContainer.findViewById<ReactTextView>(it) }
|
|
242
|
-
?.restoreSpannableFromMap()
|
|
243
|
-
bodyViewId?.let { adViewContainer.findViewById<ReactTextView>(it) }?.restoreSpannableFromMap()
|
|
244
|
-
callToActionViewId?.let { adViewContainer.findViewById<ReactTextView>(it) }
|
|
245
|
-
?.restoreSpannableFromMap()
|
|
339
|
+
try {
|
|
340
|
+
layoutMediaViewChildrenFallback()
|
|
341
|
+
} catch (_: Exception) {
|
|
342
|
+
// Ignore
|
|
343
|
+
}
|
|
246
344
|
|
|
345
|
+
try {
|
|
346
|
+
restoreRegisteredTextSpans()
|
|
247
347
|
} catch (_: Exception) {
|
|
248
348
|
// Ignore
|
|
249
349
|
}
|
|
@@ -262,6 +362,99 @@ class DaroMAdNativeViewContainer(val context: ReactContext) : ReactViewGroup(con
|
|
|
262
362
|
return null
|
|
263
363
|
}
|
|
264
364
|
|
|
365
|
+
// 미디어 그룹이 DaroMediaView가 아닌 경우(구버전 JS 조합)용 직계 자식 폴백.
|
|
366
|
+
private fun layoutMediaViewChildrenFallback() {
|
|
367
|
+
val mediaViewGroup = getMediaViewGroup() ?: return
|
|
368
|
+
if (mediaViewGroup is DaroMediaView) return
|
|
369
|
+
|
|
370
|
+
val width = mediaViewGroup.width
|
|
371
|
+
val height = mediaViewGroup.height
|
|
372
|
+
|
|
373
|
+
if (width <= 0 || height <= 0) return
|
|
374
|
+
|
|
375
|
+
mediaViewGroup.children.forEach { child ->
|
|
376
|
+
child.measure(
|
|
377
|
+
MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
|
|
378
|
+
MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)
|
|
379
|
+
)
|
|
380
|
+
|
|
381
|
+
child.layout(0, 0, width, height)
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
private fun findDaroMediaViewId(): Int? {
|
|
386
|
+
return findDaroMediaView(adViewContainer)?.id?.takeIf { it != View.NO_ID }
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
private fun findDaroMediaView(root: ViewGroup): DaroMediaView? {
|
|
390
|
+
root.children.forEach { child ->
|
|
391
|
+
if (child is DaroMediaView) return child
|
|
392
|
+
if (child is ViewGroup) findDaroMediaView(child)?.let { return it }
|
|
393
|
+
}
|
|
394
|
+
return null
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
private fun getMediaViewGroup(): ViewGroup? {
|
|
398
|
+
return mediaViewId?.let { findRegisteredAssetView(it) as? ViewGroup }
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
private fun hasRegisteredAssetView(): Boolean {
|
|
402
|
+
return titleViewId != null ||
|
|
403
|
+
bodyViewId != null ||
|
|
404
|
+
callToActionViewId != null ||
|
|
405
|
+
iconViewId != null ||
|
|
406
|
+
mediaViewId != null
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
private fun areRegisteredAssetViewsMounted(): Boolean {
|
|
410
|
+
if (!hasRegisteredAssetView()) return false
|
|
411
|
+
|
|
412
|
+
titleViewId?.let {
|
|
413
|
+
if (findRegisteredAssetView(it) !is TextView) return false
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
bodyViewId?.let {
|
|
417
|
+
if (findRegisteredAssetView(it) !is TextView) return false
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
callToActionViewId?.let {
|
|
421
|
+
if (findRegisteredAssetView(it) !is TextView) return false
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
iconViewId?.let {
|
|
425
|
+
if (findRegisteredAssetView(it) !is ImageView) return false
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
mediaViewId?.let {
|
|
429
|
+
if (findRegisteredAssetView(it) !is ViewGroup) return false
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
return true
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
private fun findRegisteredAssetView(@IdRes id: Int): View? {
|
|
436
|
+
return adViewContainer.findViewById(id)
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
private fun scheduleLoadWhenAssetViewsMounted() {
|
|
440
|
+
if (pendingLoadAssetViewRetryCount >= MAX_LOAD_ASSET_VIEW_RETRY_COUNT) {
|
|
441
|
+
pendingLoadAssetViewRetryCount = 0
|
|
442
|
+
return
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
pendingLoadAssetViewRetryCount += 1
|
|
446
|
+
loadAdHandler.removeCallbacks(retryLoadAdTask)
|
|
447
|
+
loadAdHandler.postDelayed(retryLoadAdTask, LOAD_ASSET_VIEW_RETRY_DELAY_MS)
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
private fun cancelPendingLoadIfNoRegisteredAssetView() {
|
|
451
|
+
if (hasRegisteredAssetView()) return
|
|
452
|
+
|
|
453
|
+
pendingLoadAssetViewRetryCount = 0
|
|
454
|
+
loadAdHandler.removeCallbacks(loadAdTask)
|
|
455
|
+
loadAdHandler.removeCallbacks(retryLoadAdTask)
|
|
456
|
+
}
|
|
457
|
+
|
|
265
458
|
/*
|
|
266
459
|
* Mapping View
|
|
267
460
|
* */
|
|
@@ -282,62 +475,118 @@ class DaroMAdNativeViewContainer(val context: ReactContext) : ReactViewGroup(con
|
|
|
282
475
|
private var mediaViewId: Int? = null
|
|
283
476
|
|
|
284
477
|
fun setTitleView(tag: Int) {
|
|
285
|
-
if (
|
|
478
|
+
if (tag == View.NO_ID || tag == 0) {
|
|
479
|
+
titleViewId = null
|
|
480
|
+
cancelPendingLoadIfNoRegisteredAssetView()
|
|
481
|
+
return
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
if (titleViewId == tag) return
|
|
286
485
|
|
|
287
486
|
this.titleViewId = tag
|
|
288
|
-
findViewById<ReactTextView>(tag)?.let {
|
|
289
|
-
it.moveViewsToAdViewContainer()
|
|
487
|
+
adViewContainer.findViewById<ReactTextView>(tag)?.let {
|
|
290
488
|
it.saveSpannableToMap()
|
|
291
489
|
}
|
|
490
|
+
scheduleInitialLoadIfNeeded()
|
|
292
491
|
}
|
|
293
492
|
|
|
294
493
|
fun setBodyView(tag: Int) {
|
|
295
|
-
if (
|
|
494
|
+
if (tag == View.NO_ID || tag == 0) {
|
|
495
|
+
bodyViewId = null
|
|
496
|
+
cancelPendingLoadIfNoRegisteredAssetView()
|
|
497
|
+
return
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
if (bodyViewId == tag) return
|
|
296
501
|
|
|
297
502
|
this.bodyViewId = tag
|
|
298
|
-
findViewById<ReactTextView>(tag)?.let {
|
|
299
|
-
it.moveViewsToAdViewContainer()
|
|
503
|
+
adViewContainer.findViewById<ReactTextView>(tag)?.let {
|
|
300
504
|
it.saveSpannableToMap()
|
|
301
505
|
}
|
|
506
|
+
scheduleInitialLoadIfNeeded()
|
|
302
507
|
}
|
|
303
508
|
|
|
304
509
|
fun setCallToActionView(tag: Int) {
|
|
305
|
-
if (
|
|
510
|
+
if (tag == View.NO_ID || tag == 0) {
|
|
511
|
+
callToActionViewId = null
|
|
512
|
+
cancelPendingLoadIfNoRegisteredAssetView()
|
|
513
|
+
return
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
if (callToActionViewId == tag) return
|
|
306
517
|
|
|
307
518
|
this.callToActionViewId = tag
|
|
308
|
-
findViewById<ReactTextView>(tag)?.let {
|
|
309
|
-
it.moveViewsToAdViewContainer()
|
|
519
|
+
adViewContainer.findViewById<ReactTextView>(tag)?.let {
|
|
310
520
|
it.saveSpannableToMap()
|
|
311
521
|
}
|
|
522
|
+
scheduleInitialLoadIfNeeded()
|
|
312
523
|
}
|
|
313
524
|
|
|
314
525
|
fun setIconView(tag: Int) {
|
|
315
|
-
if (
|
|
526
|
+
if (tag == View.NO_ID || tag == 0) {
|
|
527
|
+
iconViewId = null
|
|
528
|
+
cancelPendingLoadIfNoRegisteredAssetView()
|
|
529
|
+
return
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
if (iconViewId == tag) return
|
|
316
533
|
|
|
317
534
|
this.iconViewId = tag
|
|
318
|
-
|
|
535
|
+
scheduleInitialLoadIfNeeded()
|
|
319
536
|
}
|
|
320
537
|
|
|
321
538
|
fun setMediaView(tag: Int) {
|
|
322
|
-
if (
|
|
539
|
+
if (tag == View.NO_ID || tag == 0) {
|
|
540
|
+
mediaViewId = null
|
|
541
|
+
cancelPendingLoadIfNoRegisteredAssetView()
|
|
542
|
+
return
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
if (mediaViewId == tag) return
|
|
323
546
|
|
|
324
547
|
this.mediaViewId = tag
|
|
325
|
-
|
|
548
|
+
scheduleInitialLoadIfNeeded()
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
fun setAdChoicesPosition(value: String?) {
|
|
552
|
+
adChoicesPosition = when (value) {
|
|
553
|
+
"topLeft" -> DaroNativeAdChoicePlacement.TOP_LEFT
|
|
554
|
+
"topRight" -> DaroNativeAdChoicePlacement.TOP_RIGHT
|
|
555
|
+
"bottomLeft" -> DaroNativeAdChoicePlacement.BOTTOM_LEFT
|
|
556
|
+
else -> DaroNativeAdChoicePlacement.BOTTOM_RIGHT
|
|
557
|
+
}
|
|
326
558
|
}
|
|
327
559
|
|
|
328
560
|
/*
|
|
329
561
|
* Setting View
|
|
330
562
|
* */
|
|
331
563
|
|
|
332
|
-
private fun
|
|
333
|
-
|
|
564
|
+
private fun installFallbackAssetViews() {
|
|
565
|
+
adViewContainer.removeAllViews()
|
|
334
566
|
|
|
335
|
-
(
|
|
336
|
-
adViewContainer.addView(
|
|
567
|
+
titleViewId?.let { adViewContainer.addView(TextView(context).apply { id = it }) }
|
|
568
|
+
bodyViewId?.let { adViewContainer.addView(TextView(context).apply { id = it }) }
|
|
569
|
+
callToActionViewId?.let { adViewContainer.addView(TextView(context).apply { id = it }) }
|
|
570
|
+
iconViewId?.let { adViewContainer.addView(ImageView(context).apply { id = it }) }
|
|
571
|
+
mediaViewId?.let { adViewContainer.addView(FrameLayout(context).apply { id = it }) }
|
|
337
572
|
}
|
|
338
573
|
|
|
339
574
|
private val testSpanMap: MutableMap<Int, Spanned> = mutableMapOf()
|
|
340
575
|
|
|
576
|
+
private fun captureRegisteredTextSpans() {
|
|
577
|
+
titleViewId?.let { adViewContainer.findViewById<ReactTextView>(it) }?.saveSpannableToMap()
|
|
578
|
+
bodyViewId?.let { adViewContainer.findViewById<ReactTextView>(it) }?.saveSpannableToMap()
|
|
579
|
+
callToActionViewId?.let { adViewContainer.findViewById<ReactTextView>(it) }
|
|
580
|
+
?.saveSpannableToMap()
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
private fun restoreRegisteredTextSpans() {
|
|
584
|
+
titleViewId?.let { adViewContainer.findViewById<ReactTextView>(it) }?.restoreSpannableFromMap()
|
|
585
|
+
bodyViewId?.let { adViewContainer.findViewById<ReactTextView>(it) }?.restoreSpannableFromMap()
|
|
586
|
+
callToActionViewId?.let { adViewContainer.findViewById<ReactTextView>(it) }
|
|
587
|
+
?.restoreSpannableFromMap()
|
|
588
|
+
}
|
|
589
|
+
|
|
341
590
|
private fun ReactTextView.saveSpannableToMap() {
|
|
342
591
|
val text: CharSequence? = getText()
|
|
343
592
|
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
package com.daro.reactnative.view
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import android.view.View
|
|
5
|
+
import android.view.ViewGroup
|
|
6
|
+
import android.view.ViewTreeObserver
|
|
7
|
+
import android.widget.FrameLayout
|
|
8
|
+
|
|
9
|
+
class DaroMediaView(context: Context) : FrameLayout(context) {
|
|
10
|
+
|
|
11
|
+
private var relayoutPending = false
|
|
12
|
+
private var scanZeroCount = 0
|
|
13
|
+
private var scanViewCount = 0
|
|
14
|
+
private var lastZeroSignature = 0L
|
|
15
|
+
private var zeroSizeRelayoutAttempts = 0
|
|
16
|
+
|
|
17
|
+
private companion object {
|
|
18
|
+
private const val MAX_ZERO_SIZE_RELAYOUT_ATTEMPTS = 3
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
private val relayoutRunnable = Runnable {
|
|
22
|
+
relayoutPending = false
|
|
23
|
+
relayoutChildren()
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
private val preDrawListener = ViewTreeObserver.OnPreDrawListener {
|
|
27
|
+
if (width > 0 && height > 0 && childCount > 0) {
|
|
28
|
+
scanZeroCount = 0
|
|
29
|
+
scanViewCount = 0
|
|
30
|
+
scanSubtree(this)
|
|
31
|
+
|
|
32
|
+
if (scanZeroCount == 0) {
|
|
33
|
+
lastZeroSignature = 0L
|
|
34
|
+
zeroSizeRelayoutAttempts = 0
|
|
35
|
+
} else {
|
|
36
|
+
val signature = (scanZeroCount.toLong() shl 32) or scanViewCount.toLong()
|
|
37
|
+
if (signature != lastZeroSignature) {
|
|
38
|
+
lastZeroSignature = signature
|
|
39
|
+
zeroSizeRelayoutAttempts = 0
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (zeroSizeRelayoutAttempts < MAX_ZERO_SIZE_RELAYOUT_ATTEMPTS) {
|
|
43
|
+
zeroSizeRelayoutAttempts++
|
|
44
|
+
relayoutChildren()
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
true
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
override fun requestLayout() {
|
|
52
|
+
super.requestLayout()
|
|
53
|
+
scheduleRelayout()
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
override fun onViewAdded(child: View?) {
|
|
57
|
+
super.onViewAdded(child)
|
|
58
|
+
relayoutChildren()
|
|
59
|
+
scheduleRelayout()
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
override fun onAttachedToWindow() {
|
|
63
|
+
super.onAttachedToWindow()
|
|
64
|
+
relayoutChildren()
|
|
65
|
+
relayoutPending = false
|
|
66
|
+
removeCallbacks(relayoutRunnable)
|
|
67
|
+
scheduleRelayout()
|
|
68
|
+
viewTreeObserver.addOnPreDrawListener(preDrawListener)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
override fun onDetachedFromWindow() {
|
|
72
|
+
viewTreeObserver.removeOnPreDrawListener(preDrawListener)
|
|
73
|
+
removeCallbacks(relayoutRunnable)
|
|
74
|
+
relayoutPending = false
|
|
75
|
+
super.onDetachedFromWindow()
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
private fun scheduleRelayout() {
|
|
79
|
+
lastZeroSignature = 0L
|
|
80
|
+
zeroSizeRelayoutAttempts = 0
|
|
81
|
+
|
|
82
|
+
if (relayoutPending) return
|
|
83
|
+
|
|
84
|
+
relayoutPending = true
|
|
85
|
+
post(relayoutRunnable)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
private fun relayoutChildren() {
|
|
89
|
+
val width = width
|
|
90
|
+
val height = height
|
|
91
|
+
|
|
92
|
+
if (width <= 0 || height <= 0) return
|
|
93
|
+
|
|
94
|
+
for (i in 0 until childCount) {
|
|
95
|
+
val child = getChildAt(i)
|
|
96
|
+
if (child.visibility == GONE) continue
|
|
97
|
+
|
|
98
|
+
forceLayoutRecursive(child)
|
|
99
|
+
child.measure(
|
|
100
|
+
MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
|
|
101
|
+
MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)
|
|
102
|
+
)
|
|
103
|
+
child.layout(0, 0, width, height)
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
private fun forceLayoutRecursive(view: View) {
|
|
108
|
+
view.forceLayout()
|
|
109
|
+
if (view is ViewGroup) {
|
|
110
|
+
for (i in 0 until view.childCount) forceLayoutRecursive(view.getChildAt(i))
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
private fun scanSubtree(parent: ViewGroup) {
|
|
115
|
+
for (i in 0 until parent.childCount) {
|
|
116
|
+
val child = parent.getChildAt(i)
|
|
117
|
+
scanViewCount++
|
|
118
|
+
if (child.visibility != View.VISIBLE) continue
|
|
119
|
+
if (child.width <= 0 || child.height <= 0) scanZeroCount++
|
|
120
|
+
if (child is ViewGroup) scanSubtree(child)
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|