CoordinatorLayout -> ViewPager -> Fragment 가 웹뷰를 가지고 있다.
그러면 웹뷰를 스크롤하면 ViewPager의
app:layout_behavior="@string/appbar_scrolling_view_behavior"
이 동작하지 않는다. (단지 웹뷰만 스크롤 될뿐이다.)
그래서 웹뷰가 스크롤될때 상황에 따라 상위 뷰에 전파하기 가 필요하다
아래의 코드는 NestedScrollWebView 라이브러리를 커스텀 했다 (NestedScrollingChild3 로 변형하여 )
웹뷰 프레그먼트 레이아웃
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp">
<kr.beamview.view.widget.NestedScrollWebView
android:id="@+id/wv_product_description_html"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
class NestedScrollWebView @JvmOverloads constructor(
context: Context?,
attrs: AttributeSet? = null,
defStyleAttr: Int = android.R.attr.webViewStyle
) : WebView(context, attrs, defStyleAttr), NestedScrollingChild3 {
private val mScrollConsumed = IntArray(2)
private val mScrollOffset = IntArray(2)
private var mLastMotionY = 0
private var mVelocityTracker: VelocityTracker? = null
private val mMinimumVelocity: Int
private val mMaximumVelocity: Int
private val mScroller: OverScroller
private var mLastScrollerY = 0
private val mChildHelper: NestedScrollingChildHelper = NestedScrollingChildHelper(this)
init {
isNestedScrollingEnabled = true
mScroller = OverScroller(getContext())
val configuration: ViewConfiguration = ViewConfiguration.get(getContext())
mMinimumVelocity = configuration.scaledMinimumFlingVelocity
mMaximumVelocity = configuration.scaledMaximumFlingVelocity
}
override fun dispatchNestedScroll(
dxConsumed: Int,
dyConsumed: Int,
dxUnconsumed: Int,
dyUnconsumed: Int,
offsetInWindow: IntArray?,
type: Int,
consumed: IntArray
) {
mChildHelper.dispatchNestedScroll(
dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed,
offsetInWindow, type, consumed
)
}
private fun initVelocityTrackerIfNotExists() {
if (mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain()
}
}
private fun recycleVelocityTracker() {
if (mVelocityTracker != null) {
mVelocityTracker!!.recycle()
mVelocityTracker = null
}
}
private fun fling(velocityY: Int) {
startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL, ViewCompat.TYPE_NON_TOUCH)
mScroller.fling(
scrollX, scrollY, // start
0, velocityY, // velocities
0, 0, Int.MIN_VALUE, Int.MAX_VALUE, // y
0, 0
)
mLastScrollerY = scrollY
ViewCompat.postInvalidateOnAnimation(this)
}
override fun computeScroll() {
super.computeScroll()
if (mScroller.computeScrollOffset()) {
val x = mScroller.currX
val y = mScroller.currY
val dy = y - mLastScrollerY
if (dy != 0) {
val scrollY = scrollY
var dyUnConsumed = 0
var consumedY = dy
if (scrollY == 0) {
dyUnConsumed = dy
consumedY = 0
} else if (scrollY + dy < 0) {
dyUnConsumed = dy + scrollY
consumedY = -scrollY
}
if (!dispatchNestedScroll(
0, consumedY, 0, dyUnConsumed, null,
ViewCompat.TYPE_NON_TOUCH
)
) {
}
}
// Finally update the scroll positions and post an invalidation
mLastScrollerY = y
ViewCompat.postInvalidateOnAnimation(this)
} else {
// We can't scroll any more, so stop any indirect scrolling
if (hasNestedScrollingParent(ViewCompat.TYPE_NON_TOUCH)) {
stopNestedScroll(ViewCompat.TYPE_NON_TOUCH)
}
// and reset the scroller y
mLastScrollerY = 0
}
}
override fun onTouchEvent(event: MotionEvent): Boolean {
initVelocityTrackerIfNotExists()
val vtev = MotionEvent.obtain(event)
when (event.action) {
MotionEvent.ACTION_DOWN -> {
mLastMotionY = event.rawY.toInt()
startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL)
mVelocityTracker!!.addMovement(vtev)
mScroller.computeScrollOffset()
if (!mScroller.isFinished) {
mScroller.abortAnimation()
}
}
MotionEvent.ACTION_UP -> {
val velocityTracker = mVelocityTracker
velocityTracker!!.computeCurrentVelocity(1000, mMaximumVelocity.toFloat())
val initialVelocity = velocityTracker.yVelocity.toInt()
if (abs(initialVelocity) > mMinimumVelocity) {
fling(-initialVelocity)
}
stopNestedScroll()
recycleVelocityTracker()
}
MotionEvent.ACTION_CANCEL -> {
stopNestedScroll()
recycleVelocityTracker()
}
MotionEvent.ACTION_MOVE -> {
val y = event.rawY.toInt()
val deltaY = mLastMotionY - y
if (dispatchNestedPreScroll(0, deltaY, mScrollConsumed, mScrollOffset)) {
vtev.offsetLocation(0f, mScrollConsumed[1].toFloat())
}
mLastMotionY = y
val scrollY = scrollY
var dyUnconsumed = 0
if (scrollY == 0) {
dyUnconsumed = deltaY
} else if (scrollY + deltaY < 0) {
dyUnconsumed = deltaY + scrollY
vtev.offsetLocation(0f, -dyUnconsumed.toFloat())
}
mVelocityTracker!!.addMovement(vtev)
val result = super.onTouchEvent(vtev)
if (dispatchNestedScroll(
0,
deltaY - dyUnconsumed,
0,
dyUnconsumed,
mScrollOffset
)
) {
}
return result
}
else -> {
}
}
return super.onTouchEvent(vtev)
}
override fun setNestedScrollingEnabled(enabled: Boolean) {
mChildHelper.isNestedScrollingEnabled = enabled
}
override fun isNestedScrollingEnabled(): Boolean {
return mChildHelper.isNestedScrollingEnabled
}
override fun startNestedScroll(axes: Int): Boolean {
return mChildHelper.startNestedScroll(axes)
}
override fun startNestedScroll(axes: Int, type: Int): Boolean {
return mChildHelper.startNestedScroll(axes, type)
}
override fun stopNestedScroll() {
mChildHelper.stopNestedScroll()
}
override fun stopNestedScroll(type: Int) {
mChildHelper.stopNestedScroll(type)
}
override fun hasNestedScrollingParent(): Boolean {
return mChildHelper.hasNestedScrollingParent()
}
override fun hasNestedScrollingParent(type: Int): Boolean {
return mChildHelper.hasNestedScrollingParent(type)
}
override fun dispatchNestedScroll(
dxConsumed: Int, dyConsumed: Int, dxUnconsumed: Int,
dyUnconsumed: Int, offsetInWindow: IntArray?
): Boolean {
return mChildHelper.dispatchNestedScroll(
dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed,
offsetInWindow
)
}
override fun dispatchNestedScroll(
dxConsumed: Int, dyConsumed: Int, dxUnconsumed: Int,
dyUnconsumed: Int, offsetInWindow: IntArray?, type: Int
): Boolean {
return mChildHelper.dispatchNestedScroll(
dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed,
offsetInWindow, type
)
}
override fun dispatchNestedPreScroll(
dx: Int,
dy: Int,
consumed: IntArray?,
offsetInWindow: IntArray?
): Boolean {
return mChildHelper.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow)
}
override fun dispatchNestedPreScroll(
dx: Int, dy: Int, consumed: IntArray?, offsetInWindow: IntArray?,
type: Int
): Boolean {
return mChildHelper.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow, type)
}
override fun dispatchNestedFling(
velocityX: Float,
velocityY: Float,
consumed: Boolean
): Boolean {
return mChildHelper.dispatchNestedFling(velocityX, velocityY, consumed)
}
override fun dispatchNestedPreFling(velocityX: Float, velocityY: Float): Boolean {
return mChildHelper.dispatchNestedPreFling(velocityX, velocityY)
}
companion object {
private val TAG = NestedScrollWebView::class.java.simpleName
}
}
'Android' 카테고리의 다른 글
상품리스트 - 좋아요 - 툴팁 - 트러블 슈팅 (0) | 2021.06.05 |
---|---|
비동기 함수 - Rx로 변경하기 (0) | 2021.05.14 |
Map vs FlatMap (0) | 2021.04.01 |
Data class + DiffUtil 이슈 (0) | 2021.03.25 |
Jetpack Navigation Component 활용하기 (0) | 2020.11.22 |