【Kotlin/Android】ScrollViewをネスト(入れ子)して実装する方法!NestedScrollView
この記事からわかること
- Android Studio/Kotlinでネスト(入れ子)されたScrollViewの実装方法
- NestedScrollViewの使い方
index
[open]
\ アプリをリリースしました /
友達や家族の誕生日をメモ!通知も届く-みんなの誕生日-
posted withアプリーチ
環境
- Android Studio:Flamingo
- Kotlin:1.8.20
ScrollViewをネストするとスクロールできなくなる
AndroidでScrollView
の中にScrollView
を配置すると親のScrollView
はスクロールできまずが、子のScrollViewはスクロールできなくなってしまいます。
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<ScrollView
android:layout_width="match_parent"
android:layout_height="200dp">
</ScrollView>
</ScrollView>
ネストされたScrollViewをスクロールできるようにする方法
ネストされたScrollViewを動作するようにするためには以下の2つの方法があります。
- 子にNestedScrollViewを指定する
- 親にカスタムで拡張したScrollViewを指定する
子にNestedScrollViewを指定する
NestedScrollView
を使用することでネストされたScrollViewをスクロールできるようにすることが可能です。使用方法は簡単で子供側にあるScrollView
をNestedScrollView
に置き換えるだけです。
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="200dp">
</androidx.core.widget.NestedScrollView>
</ScrollView>
親にカスタムで拡張したScrollViewを指定する
NestedScrollView
を使用せずに親側のViewを変更することでネストされたScrollViewをスクロールできるようにするには親ScrollViewが子ScrollViewの縦方向のスクロールだけを許可するカスタムViewを実装します。
import android.content.Context
import android.util.AttributeSet
import android.view.MotionEvent
import android.widget.ScrollView
class CustomScrollView @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : ScrollView(context, attrs, defStyleAttr) {
private var xDistance: Float = 0f // X軸方向の移動距離を追跡するための変数
private var yDistance: Float = 0f // Y軸方向の移動距離を追跡するための変数
private var lastX: Float = 0f // 最後のX座標を記録するための変数
private var lastY: Float = 0f // 最後のY座標を記録するための変数
override fun onInterceptTouchEvent(ev: MotionEvent): Boolean {
when (ev.action) {
MotionEvent.ACTION_DOWN -> {
// タッチが開始された場合は、移動距離と座標をリセット
xDistance = 0f
yDistance = 0f
lastX = ev.x
lastY = ev.y
}
MotionEvent.ACTION_MOVE -> {
// タッチが移動した場合は、移動距離を更新
val curX: Float = ev.x
val curY: Float = ev.y
xDistance += Math.abs(curX - lastX)
yDistance += Math.abs(curY - lastY)
lastX = curX
lastY = curY
// Y方向の移動距離がX方向よりも大きい場合、親ScrollViewのスクロールを停止する
if (yDistance > xDistance) {
return false
}
}
}
// それ以外の場合は、親ScrollViewに処理を委譲
return super.onInterceptTouchEvent(ev)
}
}
あとは以下のようにXML側でカスタムViewを親に設定するだけです。
<com.sample.scrolltest.CustomScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<View
android:layout_width="match_parent"
android:layout_height="400dp"
android:background="#23527c" />
<ScrollView
android:layout_width="match_parent"
android:layout_height="200dp">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="200dp"
android:orientation="vertical">
<View
android:layout_width="match_parent"
android:layout_height="200dp"
android:background="#dd6b24" />
<View
android:layout_width="match_parent"
android:layout_height="200dp"
android:background="#000000" />
<View
android:layout_width="match_parent"
android:layout_height="200dp"
android:background="#FFF000" />
</LinearLayout>
</ScrollView>
<View
android:layout_width="match_parent"
android:layout_height="400dp"
android:background="#bd9907" />
</LinearLayout>
</com.sample.scrolltest.CustomScrollView>
まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。
ご覧いただきありがとうございました。