PageLayout 布局

PageLayou布局和前面几种布局方式是有差异的,他更倾向与动态布局,使用这个布局可以创建一个简单的多页面布局。可以在这些布局之间随意跳转,此布局每个子部件都作为一个单独的页面,所以此布局并不支持size_hintpos_hint
例如如下:
会生成一个可以自由左右拉的按钮。

# !/usr/bin/env python3
# -*- coding: utf-8 -*-

from kivy.uix.pagelayout import PageLayout
from kivy.app import App
from kivy.uix.button import Button


class PageLayoutWidget(PageLayout):
    def __init__(self, **kwargs):
        super(PageLayoutWidget, self).__init__()

        btn = Button(text='btn1', background_color=[0.3,.9,.2,1])
        btn2 = Button(text='btn2', background_color=[.1,.5,.4,1])

        self.add_widget(btn)
        self.add_widget(btn2)


class PageLayoutPyApp(App):
    def build(self):
        return PageLayoutWidget()


if __name__ == '__main__':
    PageLayoutPyApp().run()

KV实现布局

# pagelayout.kv
<PageLayoutWidget>
    border: '100dp'  # 设置边界,如果不设置默认为50dp
    Button:
        text:'Page0'
        background_color: 0.3, .2, .5, 1

    Button:
        text:'Page1'
        background_color: 0.4, .4, .6, 1

    Button:
        text:'Page2'
        background_color: 0.6, .6, .8, 1

    Button:
        text:'Page3'
        background_color: 0.8, .8, 1, 1

Python配合

# !/usr/bin/env python3
# -*- coding: utf-8 -*-

from kivy.app import App
from kivy.uix.pagelayout import PageLayout


class PageLayoutWidget(PageLayout):
    def __init__(self):
        super(PageLayoutWidget, self).__init__()


class PageLayoutApp(App):
    def build(self):
        return PageLayoutWidget()


if __name__ == '__main__':
    PageLayoutApp().run()

PageLayout布局基本属性

  • border : 指定两边边界大小,如果我们没有指定的话默认是50dp.前面的kv中也对这进行写入,测试时可以将对应行去掉后进行测试。
  • page: 设置默认显示哪一页、
  • swipe_threshold: 设置翻页灵敏度 例如: swipe_threshold: .8
  • anim_kwargs: 属性设置’t‘翻页动画和’d‘持续时间,例如: anim_kwargs: {'d':10, 't': 'linear'}。 这边t中有哪些参数暂时不做过多说明,后期会细说。

可以尝试下,当以上属性都设置了,页面之间切换的动画被延长到10秒了,并且翻页的灵敏度也要滑动到80%时以上才会被判定为翻页的动作。

RelativeLayout布局

相对布局,此布局的操作方式与前面的FloatLayout基本是相同的,只是在定位的时候我们使用的x,center_x,right,y,center_y,top这些属性是想对于他的父布局的,而不是相对于窗口。
其实任何布局,当布局的位置属性更改时,小部件都会移动。
接下来我们看看如何初始化一个RelativeLayou布局。
老样子,使用python代码和kv代码文件两种方式实现。

# !/usr/bin/env python3
# -*- coding: utf-8 -*-

from kivy.uix.relativelayout import RelativeLayout
from kivy.uix.button import Button
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.graphics import Color, Rectangle


class MyButton(Button):
    # 自定义按钮属性,将公共属性提出来
    def __init__(self, **kwargs):
        super(MyButton, self).__init__(**kwargs)
        self.font_size = 20
        self.size_hint = [.2, .2]


class RelativelayoutWidget(RelativeLayout):
    pass


class BoxLayoutWidget(BoxLayout):
    def __init__(self, **kwargs):
        super(BoxLayoutWidget, self).__init__(**kwargs)
        with self.canvas:
            Color(1, 1, 1, 1)
            self.rect = Rectangle(pos=self.pos, size=self.size)
            # 绑定事件
            self.bind(pos=self.update_rect, size=self.update_rect)

        box_relative = RelativelayoutWidget()

        btn1 = MyButton(text='btn1', pos_hint={'right': 1, 'top': 1}, background_color=(.1, .2, .3, 1))
        btn2 = MyButton(text='btn2', pos_hint={'x': 0, 'top': 1}, background_color=(.1, .2, .3, 1))
        RelativeBtn3 = MyButton(text='RelativeBtn3', pos_hint={'center_x': .5, 'center_y': .5},
                                background_color=(.1, .2, .3, 1))
        RelativeBtn4 = MyButton(text='RelativeBtn4', pos_hint={'x': 0, 'y': 0}, background_color=(.1, .2, .3, 1))
        RelativeBtn5 = MyButton(text='RelativeBtn5', pos_hint={'right': 1, 'y': 0},
                                background_color=(.1, .2, .3, 1))

        for i in [btn1, btn2, RelativeBtn3, RelativeBtn4, RelativeBtn5]:
            box_relative.add_widget(i)

        self.add_widget(BoxLayout())
        self.add_widget(box_relative)

    def update_rect(self, *args):
        # 设置背景尺寸, 可忽略
        self.rect.pos = self.pos
        self.rect.size = self.size


class RelativeLayoutApp(App):
    def build(self):
        return BoxLayoutWidget()


if __name__ == '__main__':
    RelativeLayoutApp().run()

以上代码运行后,会出现半边是空白,另外半边是有在四个角落和中间五个按钮,那是因为我们把按钮在第42行的时候,全部加在了Relativelayout布局内了,然后右边放空一个BoxLayout布局进行占位,不加任何控件,因为Relativelayout布局里面的控件是按照Relativelayout布局的位置和大小进行定位的,并非按照我们最开始初始化的大的那个BoxLayout布局进行定位的,所以里面的控件都是相对于Relativelayout布局的位置进行放置。
接下一样,我们用kv文件配合python 的方式去实现上面的样子。

# !/usr/bin/env python3
# -*- coding: utf-8 -*-

from kivy.uix.boxlayout import BoxLayout
from kivy.app import App


class BoxLayoutWidget(BoxLayout):
    def __init__(self, **kwargs):
        super(BoxLayoutWidget, self).__init__(**kwargs)


class RelativeLayoutApp(App):
    def build(self):
        return BoxLayoutWidget()


if __name__ == '__main__':
    RelativeLayoutApp().run()

kv代码

<Button>
    font_size:20
    size_hint: .2,.3

<BoxLayoutWidget>

    canvas:
        Color:
            rgba: 1,1,1,1

        Rectangle:
            size: self.size
            pos: self.pos

    BoxLayout:

    RelativeLayout:
        Button:
            text:"btn1"
            background_color: .1,.2,.3,1
            pos_hint:{'right':1, 'top':1}

        Button:
            text:"btn2"
            background_color: .1,.2,.3,1
            pos_hint:{'x': 0, 'top': 1}

        Button:
            text:"RelativeBtn3"
            background_color: .1,.2,.3,1
            pos_hint:{'center_x': .5, 'center_y': .5}

        Button:
            text:"RelativeBtn4"
            background_color: .1,.2,.3,1
            pos_hint:{'x': 0, 'y': 0}

        Button:
            text:"RelativeBtn5"
            background_color: .1,.2,.3,1
            pos_hint:{'right': 1, 'y': 0}

ScatterLayout 分散布局

ScatterLayout布局与RelativeLayout布局相似,当变更位置的时候,布局内的小部件也会随着父布局一起相对更改,因为这个布局主要由Scatter小部件实现,所以是可以实现自由的平移,旋转,缩放等布局的。
我们来看下, 使用Python是如何实现的。

# !/usr/bin/env python3
# -*- coding: utf-8 -*-

from kivy.uix.boxlayout import BoxLayout
from kivy.app import App
from kivy.uix.scatterlayout import ScatterLayout
from kivy.uix.image import AsyncImage
from kivy.graphics import Rectangle, Color


class ScatterLayoutWidget(ScatterLayout):
    pass


class BoxLayoutWidget(BoxLayout):
    def __init__(self, **kwargs):
        super(BoxLayoutWidget, self).__init__(**kwargs)

        with self.canvas:
            Color(1, 1, 1, 1)
            self.rect = Rectangle(pos=self.pos, size=self.size)
            self.bind(pos=self.update_rect, size=self.update_rect)

        scatter_layout = ScatterLayoutWidget()

        image = AsyncImage(source='https://blogcdn.sea-whales.cn/blog/typecho/11.jpg')

        scatter_layout.add_widget(image)

        self.add_widget(scatter_layout)

    def update_rect(self, *args):
        self.rect.pos = self.pos
        self.rect.size = self.size


class ScatterLayoutApp(App):
    def build(self):
        return BoxLayoutWidget()


if __name__ == '__main__':
    ScatterLayoutApp().run()

运行以上python代码,将会出现一个图片,且在窗体中间加载,我们可以使用鼠标单击图片,模拟手指点击进行图片的拖动和缩放、旋转操作。

kv配合python实现如下:


# !/usr/bin/env python3
# -*- coding: utf-8 -*-

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout


class BoxLayoutWidget(BoxLayout):
    def __init__(self, **kwargs):
        super(BoxLayoutWidget, self).__init__(**kwargs)


class ScatterLayoutApp(App):
    def build(self):
        return BoxLayoutWidget()


if __name__ == '__main__':
    ScatterLayoutApp().run()

kv文件

<BoxLayoutWidget>
    canvas:
        Color:
            rgba: 1,1,1,1

    ScatterLayout:
        AsyncImage:
            source: 'https://blogcdn.sea-whales.cn/blog/typecho/11.jpg'

    ScatterLayout:
        Image:
            source: 'scatter_image.jpg'

StackLayout 堆栈布局

堆栈布局中只要不超过布局的范围,就可以进行垂直或者水平的排列子项,并且各个小部件的大小可以不需要相同,StackLayout布局可以通过orientation属性进行指定布局方向,默认值为lr-tb
我们看看堆栈排列有哪些排序排列。

  • 按行排列:lr-tb,lr-bt,rl-tb,rl-bt
  • 按列排序:tb-lr,bt-lr,tb-rl,bt-rl

我们看看上面的l、r、t、b 分别代表什么。

  • l 代表的是'left'的缩写,代表左
  • r 代表的是'right'的缩写,代表右
  • t 代表的是'top'的缩写,代表上
  • b 代表的是'bottom'的缩写,代表下

那么我们就可以将'lr'理解为从左到右,'tb'理解为从上到下,以此类推。
'lr-tb'可以看成先按行从左到右,当前窗口行满后再按列从上到下,那么'tb-lr'则可以看成先按列从上到下,当前窗口列满后,按从左到右排列。其他方式,以此类推。

接下来我们来写一个'lr-tb'排列,不同大小的布局,且按照'lr-tb'方式布局长度递增。

# !/usr/bin/env python3
# -*- coding: utf-8 -*-


from kivy.uix.button import Button
from kivy.uix.stacklayout import StackLayout
from kivy.app import App
from kivy.graphics import Rectangle, Color


class StackLayoutWidget(StackLayout):
    def __init__(self, **kwargs):
        self.orientation = 'lr-tb'

        super(StackLayoutWidget, self).__init__(**kwargs)

        with self.canvas:
            Color(1, 1, 1, 1)  # 设置底色为白色

            self.rect = Rectangle(size=self.size, pos=self.pos)
            self.bind(size=self.update_rect, pos=self.update_rect)

        for i in range(30):
            # 将按钮的高度控制在20%,长度初始为50,随着按钮越多按钮越大递增。
            btn = Button(text=f'Btn_f{i}', width=50 + i * 8, size_hint=(None, 0.20))  
            self.add_widget(btn)

    def update_rect(self, *args):
        self.rect.pos = self.pos
        self.rect.size = self.size


class StackLayoutApp(App):
    def build(self):
        return StackLayoutWidget()


if __name__ == '__main__':
    StackLayoutApp().run()

前面已经写了很多从Python 文件改为Python和kv文件配合的情况了,这个我就不单独写了。
我们来看看StackLayout有哪些属性。

  • orientation: 前面我们说过,这个属性是用于决定布局内子部件的排列方式,也说明了具体有哪些属性。
  • padding:这个属性有看前面的也不陌生,是用于控制布局和部件之间的间距的参数。接受的是一个list,可以是四个和两个和一个。四个时分别是[padding_left, padding_top, padding_right, padding_bottom] 左、上、右、下 。两个时分别是[padding_horizontal,padding_vertical] 水平、垂直 两个方向。一个时代表控件四个方向的间距。他们的默认值都为0
  • spacing: 这属性和前面的属性也是一样的用于控制部件和部件之间间距。他可以接受两个和一个参数,也是list。不同数量参数和padding表示的一致。

以上三个参数StackLayout常用的属性,还有几个就是布局会根据子部件自动设置一些属性。我们来看下分别是哪些(顾名思义即可):

  • minimum_height:最低高度。
  • minimum_width: 最小宽度
  • minimum_size:最小尺寸(可同时设置最低高度和最小宽度)

以上就是StackLayout参见的属性,就不做例子进行解释了。如果是按照前面一步步看过来的,也能很快理解意思。