Pythonista3のui.View.flexを使い倒す

pythonista3のいまいち挙動を理解しきれなかった、ui.Viewのflex属性を色々試して理解を深めてみた。

# 最初に動きを試す

画面の四隅をドラッグすると大きさが変わるので、それぞれの動きの変化を視覚的に確認できる。

```python:ui_flex01.py
import ui

class ResizableView(ui.View):
	
	STA_IDLE = 1  # 待機
	STA_MOVE_LT = 2  # 左上移動
	STA_MOVE_LB = 3  # 左下移動
	STA_MOVE_RT = 4  # 右上移動
	STA_MOVE_RB = 5
	STA_MOVE = 6
	
	
	def __init__(self):
		self.m_state = self.STA_IDLE
		
	def touch_began(self, touch):
		l = self.width * 0.1
		r = self.width * 0.9
		t = self.height * 0.1
		b = self.height * 0.9
		
		self.m_state = self.STA_IDLE
		
		if touch.location.x < l:
			if touch.location.y < t:
				self.m_state = self.STA_MOVE_LT
			if touch.location.y >= b:
				self.m_state = self.STA_MOVE_LB
		if touch.location.x >= r:
			if touch.location.y < t:
				self.m_state = self.STA_MOVE_RT
			if touch.location.y >= b:
				self.m_state = self.STA_MOVE_RB
		
		if self.m_state == self.STA_IDLE:
			self.m_state = self.STA_MOVE
		
		
	def touch_moved(self, touch):
		s = self.m_state
		vx = touch.location.x - touch.prev_location.x
		vy = touch.location.y - touch.prev_location.y
		
		if s == self.STA_IDLE:
			pass
		elif s == self.STA_MOVE_LT:
			self.x += vx
			self.y += vy
			self.width -= vx
			self.height -= vy
		elif s == self.STA_MOVE_RT:
			self.width += vx
			self.y += vy
			self.height -= vy
		elif s == self.STA_MOVE_LB:
			self.x += vx
			self.width -= vx
			self.height += vy
		elif s == self.STA_MOVE_RB:
			self.width += vx
			self.height += vy
		elif s == self.STA_MOVE:
			self.x += vx
			self.y += vy
		
	def touch_ended(self, touch):
		self.m_state = self.STA_IDLE

datas = (
	('RB',0,0,30,30),
	('LB',270,0,30,30),
	('RT',0,370,30,30),
	('LT',270,370,30,30),
	('W',50,40,200,50),
	('H',50,100,50,250),
	('R',100,100,100,50),
	('L',100,100,100,50),
	('LR',100,100,100,50),
	('RW',100,160,100,50),
	('LW',100,220,100,50),
	('RTW',110,300,50,50),
	('LTH',200,300,50,50),
	('',150,220,100,50),
	('RW',100,280,30,50),
	('RW',150,280,30,50),
	('RW',200,280,30,50),
	('RLW',100,340,30,50),
	('RLW',150,340,30,50),
	('RLW',200,340,30,50),

)

p = ui.View()
v = ResizableView()
v.width = 300
v.height = 400
v.background_color = '#808080'
p.add_subview(v)

for d in datas:
	l = ui.Label()
	l.border_width = 2
	l.alignment = ui.ALIGN_CENTER
	l.text = l.flex = d[0]
	l.frame = (d[1],d[2],d[3],d[4])
	v.add_subview(l)


p.present('fullscreen')
v.width = p.width
v.height = p.height
```
<img width="768" alt="8874C09C-4259-42BE-8D37-BF99880219CE.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36064/a203e364-9ba6-dab8-2ec7-737e89281c1c.png">




# flex の機能

flex を設定すると、親 View のサイズ変更に合わせて、自分の位置 (x,y) や大きさ (width,height) が自動的に変わるようにする事が可能です。

指定可能なのは R, B, L, T, W, H の文字で、複数組み合わせて指定する事も可能です。

# デフォルト ‘’、’R’、’RB’

flex に空文字を指定すると、x,y,width,height は親 View のサイズ変更の影響を受けません。
これは ‘R’ や　‘RB’ を指定した時と同じ挙動です。

# 右端に吸着 ‘L’

flex に ‘L’ を指定すると flexible left margine。直訳すると左の余白が柔軟に変化する。意訳すると親 View の右端に吸着します。

これは、親 View の大きさが変わった時にこの View が右寄りを維持する事になります。

# それぞれの端に吸着　‘R’、’B’、’T’

‘L’ 同様に

‘R’ は親 View の左端に吸着
‘B’ は親 View の上端に吸着。(デフォルトの挙動)
‘T’ は親 View の下端に吸着

となります。

個人的には LRBT の意味が真逆のイメージなのですが、そう思うのは私だけでしょうか？

# 大きさを追従 ‘W’、’H’

‘W’ を指定すると親の大きさ変更に合わせて幅が変わります。
‘H’ を指定すると親の大きさ変更に合わせて高さが変わります。

# 親View上の相対位置を維持　‘RL’、’BT’

親の大きさが変わっても、複数のボタンを等間隔に配置したい。という時に使用します。
たいていは大きさも合わせて変化させる必要があるので、W H も加えて、’RLW’、’BTH’ を使う事が多いと思います。