Skip to content
This repository was archived by the owner on Aug 13, 2024. It is now read-only.

Commit 1c7c4aa

Browse files
committed
chore: remove ios, update android base component
1 parent e7177c9 commit 1c7c4aa

21 files changed

+15828
-400
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@ npm install react-native-scrollview-enhancer
1111
## Usage
1212

1313
```js
14-
import { ScrollviewEnhancerView } from "react-native-scrollview-enhancer";
14+
import { ScrollViewEnhancerView } from "react-native-scrollview-enhancer";
1515

1616
// ...
1717

18-
<ScrollviewEnhancerView color="tomato" />
18+
<ScrollViewEnhancerView color="tomato" />
1919
```
2020

2121
## Contributing

android/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ dependencies {
7979
if (isNewArchitectureEnabled()) {
8080
react {
8181
jsRootDir = file("../src/")
82-
libraryName = "ScrollviewEnhancerView"
82+
libraryName = "ScrollViewEnhancerView"
8383
codegenJavaPackageName = "com.scrollviewenhancer"
8484
}
8585
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
package com.scrollviewenhancer
2+
3+
import android.content.Context
4+
import android.util.Log
5+
import com.facebook.react.views.scroll.ReactHorizontalScrollView
6+
import com.facebook.react.views.scroll.ReactScrollView
7+
import com.facebook.react.views.view.ReactViewGroup
8+
9+
10+
class EnhancerFragment(context: Context): ReactViewGroup(context) {
11+
var NAME = "SENDBIRD"
12+
private var mMaintainVisibleContentPositionHelper: MaintainVisibleScrollPositionHelper? = null
13+
14+
private fun getChildHorizontalScrollView(): ReactHorizontalScrollView? {
15+
Log.d(NAME, "getChildHorizontalScrollView()")
16+
this.childCount.let {
17+
Log.d(NAME, "getChildHorizontalScrollView()/childCount$it")
18+
for (i in 0 until it) {
19+
val view = this.getChildAt(i)
20+
if (view is ReactHorizontalScrollView) {
21+
Log.d(NAME, "getChildHorizontalScrollView()/found ReactHorizontalScrollView $view")
22+
return view
23+
}
24+
}
25+
return null
26+
}
27+
}
28+
29+
private fun getChildVerticalScrollView(): ReactScrollView? {
30+
Log.d(NAME, "getChildVerticalScrollView()")
31+
this.childCount.let {
32+
Log.d(NAME, "getChildVerticalScrollView()/childCount$it")
33+
for (i in 0 until it) {
34+
val view = this.getChildAt(i)
35+
if (view is ReactScrollView) {
36+
Log.d(NAME, "getChildVerticalScrollView()/found ReactScrollView $view")
37+
return view
38+
}
39+
}
40+
return null
41+
}
42+
}
43+
44+
fun setMaintainVisibleContentPosition(config: MaintainVisibleScrollPositionHelper.Config?) {
45+
Log.d(NAME, "setMaintainVisibleContentPosition $config")
46+
47+
if (config != null && mMaintainVisibleContentPositionHelper == null) {
48+
mMaintainVisibleContentPositionHelper = getChildHorizontalScrollView()?.let {
49+
MaintainVisibleScrollPositionHelperH(it, false)
50+
} ?: run {
51+
getChildVerticalScrollView()?.let {
52+
MaintainVisibleScrollPositionHelperV(it, false)
53+
}
54+
}
55+
mMaintainVisibleContentPositionHelper?.start()
56+
} else if (config == null && mMaintainVisibleContentPositionHelper != null) {
57+
mMaintainVisibleContentPositionHelper?.stop()
58+
mMaintainVisibleContentPositionHelper = null
59+
}
60+
61+
if (mMaintainVisibleContentPositionHelper != null) {
62+
mMaintainVisibleContentPositionHelper?.setConfig(config)
63+
}
64+
}
65+
66+
override fun onAttachedToWindow() {
67+
Log.d(NAME, "onAttachedToWindow")
68+
super.onAttachedToWindow()
69+
mMaintainVisibleContentPositionHelper?.start()
70+
}
71+
72+
override fun onDetachedFromWindow() {
73+
Log.d(NAME, "onDetachedFromWindow")
74+
super.onDetachedFromWindow()
75+
mMaintainVisibleContentPositionHelper?.stop()
76+
}
77+
78+
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
79+
Log.d(NAME, "onLayout $changed")
80+
super.onLayout(changed, left, top, right, bottom)
81+
mMaintainVisibleContentPositionHelper?.updateScrollPosition()
82+
}
83+
}
Lines changed: 292 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,292 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
package com.scrollviewenhancer
8+
9+
import android.graphics.Rect
10+
import android.view.View
11+
import com.facebook.infer.annotation.Assertions
12+
import com.facebook.react.bridge.*
13+
import com.facebook.react.uimanager.UIManagerHelper
14+
import com.facebook.react.uimanager.common.ViewUtil
15+
import com.facebook.react.views.scroll.ReactHorizontalScrollView
16+
import com.facebook.react.views.scroll.ReactScrollView
17+
import com.facebook.react.views.view.ReactViewGroup
18+
import java.lang.ref.WeakReference
19+
20+
21+
abstract class MaintainVisibleScrollPositionHelper {
22+
class Config internal constructor(
23+
val minIndexForVisible: Int,
24+
val autoScrollToTopThreshold: Int?
25+
) {
26+
companion object {
27+
fun fromReadableMap(value: ReadableMap): Config {
28+
val minIndexForVisible: Int = value.getInt("minIndexForVisible")
29+
val autoScrollToTopThreshold: Int? =
30+
if (value.hasKey("autoscrollToTopThreshold")) value.getInt("autoscrollToTopThreshold") else null
31+
return Config(minIndexForVisible, autoScrollToTopThreshold)
32+
}
33+
}
34+
}
35+
36+
protected var mConfig: Config? = null
37+
fun setConfig(config: Config?) {
38+
mConfig = config
39+
}
40+
abstract fun start(): Unit
41+
abstract fun stop(): Unit
42+
abstract fun updateScrollPosition(): Unit
43+
}
44+
45+
46+
/**
47+
* Manage state for the maintainVisibleContentPosition prop.
48+
*
49+
* This uses UIManager to listen to updates and capture position of items before and after layout.
50+
*/
51+
class MaintainVisibleScrollPositionHelperV(
52+
private val mScrollView: ReactScrollView,
53+
private val mHorizontal: Boolean = false
54+
): UIManagerListener, MaintainVisibleScrollPositionHelper() {
55+
private var mFirstVisibleView: WeakReference<View>? = null
56+
private var mPrevFirstVisibleFrame: Rect? = null
57+
private var mListening: Boolean = false
58+
59+
/**
60+
* Start listening to view hierarchy updates. Should be called when this is created.
61+
*/
62+
override fun start() {
63+
if (mListening) {
64+
return
65+
}
66+
mListening = true
67+
uIManagerModule.addUIManagerEventListener(this)
68+
}
69+
70+
/**
71+
* Stop listening to view hierarchy updates. Should be called before this is destroyed.
72+
*/
73+
override fun stop() {
74+
if (!mListening) {
75+
return
76+
}
77+
mListening = false
78+
uIManagerModule.removeUIManagerEventListener(this)
79+
}
80+
81+
/**
82+
* Update the scroll position of the managed ScrollView. This should be called after layout
83+
* has been updated.
84+
*/
85+
override fun updateScrollPosition() {
86+
if ((mConfig == null
87+
) || (mFirstVisibleView == null
88+
) || (mPrevFirstVisibleFrame == null)
89+
) {
90+
return
91+
}
92+
val firstVisibleView: View? = mFirstVisibleView!!.get()
93+
val newFrame: Rect = Rect()
94+
firstVisibleView!!.getHitRect(newFrame)
95+
if (mHorizontal) {
96+
val deltaX: Int = newFrame.left - mPrevFirstVisibleFrame!!.left
97+
if (deltaX != 0) {
98+
val scrollX: Int = mScrollView.scrollX
99+
mScrollView.scrollTo(scrollX + deltaX, mScrollView.scrollY)
100+
mPrevFirstVisibleFrame = newFrame
101+
if (mConfig!!.autoScrollToTopThreshold != null && scrollX <= mConfig!!.autoScrollToTopThreshold!!) {
102+
mScrollView.reactSmoothScrollTo(0, mScrollView.scrollY)
103+
}
104+
}
105+
} else {
106+
val deltaY: Int = newFrame.top - mPrevFirstVisibleFrame!!.top
107+
if (deltaY != 0) {
108+
val scrollY: Int = mScrollView.scrollY
109+
mScrollView.scrollTo(mScrollView.scrollX, scrollY + deltaY)
110+
mPrevFirstVisibleFrame = newFrame
111+
if (mConfig!!.autoScrollToTopThreshold != null && scrollY <= mConfig!!.autoScrollToTopThreshold!!) {
112+
mScrollView.reactSmoothScrollTo(mScrollView.scrollX, 0)
113+
}
114+
}
115+
}
116+
}
117+
118+
private val contentView: ReactViewGroup
119+
get() = mScrollView.getChildAt(0) as ReactViewGroup
120+
121+
private val uIManagerModule: UIManager
122+
get() = Assertions.assertNotNull(
123+
UIManagerHelper.getUIManager(
124+
mScrollView.context as ReactContext,
125+
ViewUtil.getUIManagerType(mScrollView.id)
126+
)
127+
)
128+
129+
private fun computeTargetView() {
130+
if (mConfig == null) {
131+
return
132+
}
133+
val contentView: ReactViewGroup? = contentView
134+
if (contentView == null) {
135+
return
136+
}
137+
val currentScroll: Int = if (mHorizontal) mScrollView!!.scrollX else mScrollView!!.scrollY
138+
for (i in mConfig!!.minIndexForVisible until contentView.childCount) {
139+
val child: View = contentView.getChildAt(i)
140+
val position: Float = if (mHorizontal) child.x else child.y
141+
if (position > currentScroll || i == contentView.childCount - 1) {
142+
mFirstVisibleView = WeakReference(child)
143+
val frame: Rect = Rect()
144+
child.getHitRect(frame)
145+
mPrevFirstVisibleFrame = frame
146+
break
147+
}
148+
}
149+
}
150+
151+
// UIManagerListener
152+
override fun willDispatchViewUpdates(uiManager: UIManager) {
153+
UiThreadUtil.runOnUiThread(
154+
object : Runnable {
155+
override fun run() {
156+
computeTargetView()
157+
}
158+
})
159+
}
160+
161+
override fun didDispatchMountItems(uiManager: UIManager) {
162+
// noop
163+
}
164+
165+
override fun didScheduleMountItems(uiManager: UIManager) {
166+
// noop
167+
}
168+
}
169+
170+
/**
171+
* Manage state for the maintainVisibleContentPosition prop.
172+
*
173+
* This uses UIManager to listen to updates and capture position of items before and after layout.
174+
*/
175+
class MaintainVisibleScrollPositionHelperH(
176+
private val mScrollView: ReactHorizontalScrollView,
177+
private val mHorizontal: Boolean = false
178+
): UIManagerListener, MaintainVisibleScrollPositionHelper() {
179+
private var mFirstVisibleView: WeakReference<View>? = null
180+
private var mPrevFirstVisibleFrame: Rect? = null
181+
private var mListening: Boolean = false
182+
183+
/**
184+
* Start listening to view hierarchy updates. Should be called when this is created.
185+
*/
186+
override fun start() {
187+
if (mListening) {
188+
return
189+
}
190+
mListening = true
191+
uIManagerModule.addUIManagerEventListener(this)
192+
}
193+
194+
/**
195+
* Stop listening to view hierarchy updates. Should be called before this is destroyed.
196+
*/
197+
override fun stop() {
198+
if (!mListening) {
199+
return
200+
}
201+
mListening = false
202+
uIManagerModule.removeUIManagerEventListener(this)
203+
}
204+
205+
/**
206+
* Update the scroll position of the managed ScrollView. This should be called after layout
207+
* has been updated.
208+
*/
209+
override fun updateScrollPosition() {
210+
if ((mConfig == null
211+
) || (mFirstVisibleView == null
212+
) || (mPrevFirstVisibleFrame == null)
213+
) {
214+
return
215+
}
216+
val firstVisibleView: View? = mFirstVisibleView!!.get()
217+
val newFrame: Rect = Rect()
218+
firstVisibleView!!.getHitRect(newFrame)
219+
if (mHorizontal) {
220+
val deltaX: Int = newFrame.left - mPrevFirstVisibleFrame!!.left
221+
if (deltaX != 0) {
222+
val scrollX: Int = mScrollView.scrollX
223+
mScrollView.scrollTo(scrollX + deltaX, mScrollView.scrollY)
224+
mPrevFirstVisibleFrame = newFrame
225+
if (mConfig!!.autoScrollToTopThreshold != null && scrollX <= mConfig!!.autoScrollToTopThreshold!!) {
226+
mScrollView.reactSmoothScrollTo(0, mScrollView.scrollY)
227+
}
228+
}
229+
} else {
230+
val deltaY: Int = newFrame.top - mPrevFirstVisibleFrame!!.top
231+
if (deltaY != 0) {
232+
val scrollY: Int = mScrollView.scrollY
233+
mScrollView.scrollTo(mScrollView.scrollX, scrollY + deltaY)
234+
mPrevFirstVisibleFrame = newFrame
235+
if (mConfig!!.autoScrollToTopThreshold != null && scrollY <= mConfig!!.autoScrollToTopThreshold!!) {
236+
mScrollView.reactSmoothScrollTo(mScrollView.scrollX, 0)
237+
}
238+
}
239+
}
240+
}
241+
242+
private val contentView: ReactViewGroup
243+
get() = mScrollView.getChildAt(0) as ReactViewGroup
244+
245+
private val uIManagerModule: UIManager
246+
get() = Assertions.assertNotNull(
247+
UIManagerHelper.getUIManager(
248+
mScrollView.context as ReactContext,
249+
ViewUtil.getUIManagerType(mScrollView.id)
250+
)
251+
)
252+
253+
private fun computeTargetView() {
254+
if (mConfig == null) {
255+
return
256+
}
257+
val contentView: ReactViewGroup? = contentView
258+
if (contentView == null) {
259+
return
260+
}
261+
val currentScroll: Int = if (mHorizontal) mScrollView!!.scrollX else mScrollView!!.scrollY
262+
for (i in mConfig!!.minIndexForVisible until contentView.childCount) {
263+
val child: View = contentView.getChildAt(i)
264+
val position: Float = if (mHorizontal) child.x else child.y
265+
if (position > currentScroll || i == contentView.childCount - 1) {
266+
mFirstVisibleView = WeakReference(child)
267+
val frame: Rect = Rect()
268+
child.getHitRect(frame)
269+
mPrevFirstVisibleFrame = frame
270+
break
271+
}
272+
}
273+
}
274+
275+
// UIManagerListener
276+
override fun willDispatchViewUpdates(uiManager: UIManager) {
277+
UiThreadUtil.runOnUiThread(
278+
object : Runnable {
279+
override fun run() {
280+
computeTargetView()
281+
}
282+
})
283+
}
284+
285+
override fun didDispatchMountItems(uiManager: UIManager) {
286+
// noop
287+
}
288+
289+
override fun didScheduleMountItems(uiManager: UIManager) {
290+
// noop
291+
}
292+
}

0 commit comments

Comments
 (0)