カスタムビュー
子Viewを複数箇所で使用する場合や、
処理を独立させたい場合にカスタムビューを使用する。
更に子Viewを表示している間は後ろのViewにタッチを伝搬させないようにする。
実装
ActivityにaddViewする先の親ViewであるFrameLayoutを保持する
Activity
activity_main.xml
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- 子Viewが表示中、このScrollViewがスクロールされなければOK -->
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/gradation">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="1000dp"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="500dp"
android:text="activity_main top"
android:textSize="30sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="activity_main bottom"
android:textSize="30sp" />
</LinearLayout>
</ScrollView>
<!-- 親View -->
<FrameLayout
android:id="@+id/customViewContainer"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</FrameLayout>
MainActivity.kt
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// 親View
val container = findViewById<FrameLayout>(R.id.customViewContainer)
// 子View
val firstCustomView = FirstCustomView(this, {
container.removeAllViews() // 親Viewに設定した子Viewを削除
})
// 親Viewに子viewを設定
container.addView(firstCustomView)
}
}
カスタムビュー(子View)
widget_custom_view.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#66000000">
<FrameLayout
android:layout_gravity="center"
android:layout_width="300dp"
android:layout_height="300dp"
android:background="@android:color/black">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="custom view first"
android:textColor="@android:color/white"
android:textSize="30sp" />
<Button
android:id="@+id/customFirstButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center"
android:layout_marginBottom="30dp"
android:text="close"
android:textColor="@android:color/black" />
</FrameLayout>
</FrameLayout>
FirstCustomView.kt
class FirstCustomView(context: Context): FrameLayout(context) {
var onClick: (()->Unit)? = null
constructor(context: Context, onClick: ()->Unit): this(context){
this.onClick = onClick
}
init{
// Viewを設定
inflate(context, R.layout.widget_custom_first, this)
findViewById<Button>(R.id.customFirstButton)?.setOnClickListener {
onClick?.invoke()
}
// 背後のViewへタッチを伝搬させない
// これがないと後ろのスクロールViewがスクロールできてしまう
setOnTouchListener { _, _ -> true }
}
}
結果
スクリーンショット
子view表示時 - スクロール不可
CLOSEタップして子View削除後
スクロール可能に
説明
親ViewのContainerにFrameLayoutを継承した子ViewのFirstCustomViewを
addView()にて設定
// 親Viewに子viewを設定
container.addView(firstCustomView)
子Viewの"CLOSE"Buttonをタップした際にActivityへタップされたことを通知
親ViewにてremoveAllView()にて子Viewを削除。
// 子View
val firstCustomView = FirstCustomView(this, {
container.removeAllViews() // 親Viewに設定した子Viewを削除
})
使い勝手が非常に良いので、中規模以上のアプリでは使用すると良い感じです。