Kivy ScrollViewの基本

#ScrollView


![scrollのコピー.gif](https://qiita-image-store.s3.amazonaws.com/0/305953/a7b098a0-8fe7-330d-da19-7c0a714fc34b.gif)

```python:main.py
from kivy.app import App

class MainApp(App):
    pass

if __name__ == "__main__":
    MainApp().run()
```

```python:main.kv
ScrollView:
    GridLayout:
        cols:2
        size_hint_y: None
        row_default_height: 200
        height: self.minimum_height
        Button:
            text: "1"
        Button:
            text: "2"
        Button:
            text: "3"
        Button:
            text: "4"
        Button:
            text: "5"
        Button:
            text: "6"
        Button:
            text: "7"
        Button:
            text: "8"
        Button:
            text: "9"
        Button:
            text: "10"
        Button:
            text: "11"
        Button:
            text: "12"
```

上の例はこのようなコードで実現できます

見て分かる通りScrollViewの子WidgetであるGridLayoutがスクロール可能になっています。
この様にスクロールを実現するには***スクロール可能にしたいWidgetをScrollViewの子とする***だけです。
しかし、ただ子にするだけではスクロールできる状態にならず以下の様な**いくつかの指定**をする必要があります

```python:.kv
        size_hint_y: None
        row_default_height: 200
        height: self.minimum_height
```

何故これが必要なのか、何故これで実現されるのかを見ていきたいと思います

##基本的な考え方
ScrollViewによってスクロール可能な状態にする為には、
子Widgetのheight/widthいずれかを下図の様に親Widgetのheight/widthより大きくする必要があります。


![スクリーンショット 2018-10-28 19.44.30.png](https://qiita-image-store.s3.amazonaws.com/0/305953/da0cc482-0d3a-ca25-6a75-5d1f69dbb8bc.png)





これを実現する為の条件は2つだけで上の例ではそれを満たしています。


スクロール可能条件
①子Widgetが親Widget内に収まらない状態を可能する
②子Widgetのheght/widthを親Widgetのheight/widthより大きくする


これらが具体的にどのように実現されるのかを見てみます

##実際の方法

上の２つの条件を満たす為には以下の方法が考えられます(他の方法もあるかもしれません)

方法1. 子Widgetのsize_hintの値を1より大きくする
方法2. 子Widgetのsize_hintの値をNoneにして、子Widgetのheightを調整する


以下、親WidgetがScrollView(rootかつsize_hint:default),子WidgetがGridLayoutの場合の例を考えます

###方法1 : 子Widgetのsize_hintを１より大きくする
まず子Widgetのsize_hintの値というのは
***それ自身もしくはそれ自身の全ての子Widgetが(親Widgetのwidth×size_hint_x)×(親Widgetのheight×size_hint_y)に収まる***ようにLayoutのサイズを自動調整するためのものであるという前提があります(下図参照)



↓size_hint_y: 1 (default)
![スクリーンショット 2018-10-26 23.07.35.png](https://qiita-image-store.s3.amazonaws.com/0/305953/37c02b6f-62dd-030a-033b-33c332e4d104.png)

↓size_hint_y: 0.5
![スクリーンショット 2018-10-26 23.06.28.png](https://qiita-image-store.s3.amazonaws.com/0/305953/4218be9d-6e0a-df8e-bbf7-b41f36092b32.png)

↓size_hint_y:4
![スクリーンショット 2018-10-26 23.04.00.png](https://qiita-image-store.s3.amazonaws.com/0/305953/4506f37e-5d08-b775-0a22-0283850e7a6a.png)

従って,これを1より大きくすることでスクロールを実現する条件①、②を満たします
1以下では条件①を満たさずスクロール可能にはなりません

方法1を具体的に示すと以下の様な構造が考えられます

```python:main.kv
ScrollView:
    GridLayout:
        cols:2
        size_hint_x: 3 #任意の1より大きい値
        size_hint_y: 2 #任意の1より大きい値
        #以下任意のWidget
```

この場合Layoutとその中のWidgetのサイズが***画面サイズによって可変的に決められ自分で設定することが出来ない***のが特徴です

一方,方法2では子Widgetのサイズを固定することができます

###方法2 : 子Widgetのsize_hintの値をNoneにして、そのheightを調整する
Widgetのsize_hintをNoneにするとWidgetは指定されたheight/widthに固定されます。(GridLayoutの場合defaultではheight/weightともに100)
これを利用して、子Widgetのheight/widthを画面サイズ以上の値を指定することで条件①、②を満たしスクロール可能にするのが方法2です


↓size_hint: None, Noneの状態
![スクリーンショット 2018-10-26 23.55.22.png](https://qiita-image-store.s3.amazonaws.com/0/305953/51c03370-9239-5a8d-603f-6b0711abad1a.png)


具体的には以下の様な構成が考えられます

```python:main.kv
ScrollView:
    GridLayout:
        cols:2
        size_hint_y: None  #スクロール可能条件①を満たす
        row_default_height: 200  #rowのheightを指定
        height: self.minimum_height
        #(画面サイズ<self.minimum_heightの場合)スクロール可能条件②を満たす
        #以下任意のWidget
```

size_hintがNoneになっていない、またはLayoutのheightが画面サイズ以上に指定されていない場合は条件を満たさずスクロール可能にはならないので注意が必要です。
たとえ**Layout内のWidgetのサイズの合計が画面サイズを超えていても**スクロール可能にはなりません

また、

```python:.kv
height: self.minimum_height
width: self.minimum_width
```

という指定をすることでLayoutのサイズが子ウィジットが全て収まる最小のサイズになるように設定されます
ここを任意の数字にしてしまうと、row_defaultやcol_defaultより優先されてしまい意図したウィジットサイズにならないので注意が必要です

##その他の例

###BoxLayout
![名称未設定.gif](https://qiita-image-store.s3.amazonaws.com/0/305953/def23407-8a03-9b97-4bef-4a056dd3dbc4.gif)


```python:main.kv
ScrollView:
    BoxLayout:
        size_hint_y: None
        orientation: "vertical"
        height: self.minimum_height
        Label:
            size_hint_y: None
            text: "1"
            height: 500
        Button:
            size_hint_y: None
            text: "2"
        Label:
            size_hint_y: None
            text: "3"
        ToggleButton:
            size_hint_y: None
            text: "4"
```

###Label

```python:main.kv
ScrollView:
    Label:
        size_hint: None, None
        text: "testtesttest"
        size: 2000,2000
        font_size: 300
        canvas.before:
            Color:
                rgba: 0.9,0,0.3,1
            Rectangle:
                size: self.size
                pos: self.pos
```