Kivy.garden.NavigationDrawer

totally copied from github opensource code. Just a translation and ideas with idividuals ideas to share its use for all people using chinese.

Copyright © 2013 Alexander Taylor
开源免责免费使用声明:
#Permission is hereby granted, free of charge, to any person obtaining a copy
#of this software and associated documentation files (the “Software”), to deal
#in the Software without restriction, including without limitation the rights
#to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
#copies of the Software, and to permit persons to whom the Software is

#furnished to do so, subject to the following conditions:

#The above copyright notice and this permission notice shall be included in
#all copies or substantial portions of the Software.
substantial 美/səbˈstænʃ(ə)l/  adj 真实的; 
portion 美/ˈpɔːrʃ(ə)n/ n.(责任、过失、职责等的)一份,一部分;<法律>(根据法律赠与或遗留给继承人的)一份财产;

#THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
#IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
#FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
#AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
#LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
#THE SOFTWARE.

‘’'NavigationDrawer

The NavigationDrawer widget provides a hidden panel view designed to
duplicate the popular Android layout. The user views one main widget
but can slide from the left of the screen to view a second, previously
hidden widget. The transition between open/closed is smoothly
animated, with the parameters (anim time, panel width, touch
detection) all user configurable. If the panel is released without
being fully open or closed, it animates to an appropriate
configuration.
这NavigationDrawer组件儿 提供了一个隐藏的panel view仪表盘视图,这
视图是被设计来复制流行的Android布局的。使用者观看一个主要的组件,
但是可以在一秒内从屏幕的左边滑动到视图,先前地被隐藏的组件。
【就是说咱看着当前一个屏幕呢,可以滑动到另一个之前被隐藏好的组件儿】
这在打开/关闭地滑动转变间是顺畅的动画儿,掺和着一些元素儿(anim time,
动画时间,panel width, 仪表盘宽度,touch detection触发事件)所有的是
使用者可构建的。如果这仪表盘儿被展示没全乎或者没关全乎,(留着一绺子)
,它动画到一个合适的配置。 【就说配置可以调】

NavigationDrawer supports many different animation properties,
including moving one or both of the side/main panels, darkening
either/both widgets, changing side panel opacity, and changing which
widget is on top. The user can edit these individually to taste (this
is enough rope to hang oneself, it’s easy to make a useless or silly
configuration!), or use one of a few preset animations.

NavigationDrawer支持许多不同的动画属性,包括移动一个或多个的
幻灯片/主仪表盘,也可也已使这两者变黑1个或多个组件,改变幻灯片
仪表盘透明度,和改变哪个组件在上。使用者可以自己改变这些来尝试
(这是足够的大圈儿来掉某个东西了,也非常简单来制作一个没啥用或
呆板的配置),或使用些许里的一个原开发者已经事先准备好的动画儿。

赘述: 这大圈啥意思呢?就好比说牛仔整个圈套牛脖子,圈小了套不进去。
就是诙谐地说明咱这配置整些简单地绰绰有余。

The hidden panel might normally a set of navigation buttons, but the
implementation lets the user use any widget(s).

隐藏的仪表盘可能主要是一些导航按钮,但执行允许用户使用任何组件。

The first widget added to the NavigationDrawer is automatically used
as the side panel, and the second widget as the main panel. No further
widgets can be added, further changes are left to the user via editing
the panel widgets.

第一个被添加到NavigationDrawer的组件是自动被当作 侧仪表盘 使用的,【
也就是说如果咱不使用仪表盘,咱就先给他一个空组件占地儿,这面儿
必须给到,这就是规矩】,并且第二个组件是当作 主要仪表盘。没有其他更
多的组件可以被添加了,其他的改动空间是剩来给用户通过修改这俩仪表盘组件了。

Usage summary 使用总结

  • The first widget added to a NavigationDrawer is used as the hidden
    side panel.
    第一个组件被添加到一个NavagationDrawer是被用来当作隐藏的 侧边
    仪表盘
    的。

  • The second widget added is used as the main panel.

被添加的第二个组件时用来当作主要仪表盘的。

remove_widget

Both widgets can be removed with remove_widget, or alternatively
set/removed with set_main_panel and set_side_panel.
这俩组件都可以被remove_widget移除, 或者第二种方法, 被
set_main_panel 和set_side_panel设置/移除。

set_main_panel

set_side_panel

  • The hidden side panel can be revealed by dragging from the left of
    the NavigationDrawer. The touch detection width is the
    touch_accept_width property.
    被隐藏的 侧仪表盘 可以被显示通过Navigation Drawer的左侧。触摸执行宽
    度是touch_accept_width属性。

touch_accept_width

  • Every animation property is user-editable, or default animations
    can be chosen by setting anim_type.
    每个动画属性是用户可编辑的,或者默认动画可以被选择通过设置
    anim_type

anim_type

See the example and docstrings for information on individual properties.
看看下面的案例和文档获取在个体属性方面的知识。

Example::

class ExampleApp(App):

    def build(self):
        navigationdrawer = NavigationDrawer()

        side_panel = BoxLayout(orientation='vertical')
        side_panel.add_widget(Label(text='Panel label'))
        side_panel.add_widget(Button(text='A button'))
        side_panel.add_widget(Button(text='Another button'))
        navigationdrawer.add_widget(side_panel)

        label_head = (
            '[b]Example label filling main panel[/b]\n\n[color=ff0000](p'
            'ull from left to right!)[/color]\n\nIn this example, the le'
            'ft panel is a simple boxlayout menu, and this main panel is'
            ' a BoxLayout with a label and example image.\n\nSeveral pre'
            'set layouts are available (see buttons below), but users ma'
            'y edit every parameter for much more customisation.')
        main_panel = BoxLayout(orientation='vertical')
        label_bl = BoxLayout(orientation='horizontal')
        label = Label(text=label_head, font_size='15sp',
                      markup=True, valign='top')
        label_bl.add_widget(Widget(size_hint_x=None, width=dp(10)))
        label_bl.add_widget(label)
        label_bl.add_widget(Widget(size_hint_x=None, width=dp(10)))
        main_panel.add_widget(Widget(size_hint_y=None, height=dp(10)))
        main_panel.add_widget(label_bl)
        main_panel.add_widget(Widget(size_hint_y=None, height=dp(10)))
        navigationdrawer.add_widget(main_panel)
        label.bind(size=label.setter('text_size'))

        def set_anim_type(name):
            navigationdrawer.anim_type = name
        modes_layout = BoxLayout(orientation='horizontal')
        modes_layout.add_widget(Label(text='preset\nanims:'))
        slide_an = Button(text='slide_\nabove_\nanim')
        slide_an.bind(on_press=lambda j: set_anim_type('slide_above_anim'))
        slide_sim = Button(text='slide_\nabove_\nsimple')
        slide_sim.bind(on_press=lambda j: set_anim_type('slide_above_simple'))
        fade_in_button = Button(text='fade_in')
        fade_in_button.bind(on_press=lambda j: set_anim_type('fade_in'))
        reveal_button = Button(text='reveal_\nbelow_\nanim')
        reveal_button.bind(on_press=
                           lambda j: set_anim_type('reveal_below_anim'))
        slide_button = Button(text='reveal_\nbelow_\nsimple')
        slide_button.bind(on_press=
                          lambda j: set_anim_type('reveal_below_simple'))
        modes_layout.add_widget(slide_an)
        modes_layout.add_widget(slide_sim)
        modes_layout.add_widget(fade_in_button)
        modes_layout.add_widget(reveal_button)
        modes_layout.add_widget(slide_button)
        main_panel.add_widget(modes_layout)

        button = Button(text='toggle NavigationDrawer state (animate)',
                        size_hint_y=0.2)
        button.bind(on_press=lambda j: navigationdrawer.toggle_state())
        button2 = Button(text='toggle NavigationDrawer state (jump)',
                         size_hint_y=0.2)
        button2.bind(on_press=lambda j: navigationdrawer.toggle_state(False))
        button3 = Button(text='toggle _main_above', size_hint_y=0.2)
        button3.bind(on_press=navigationdrawer.toggle_main_above)
        main_panel.add_widget(button)
        main_panel.add_widget(button2)
        main_panel.add_widget(button3)

        return navigationdrawer

    ExampleApp().run()

'''

__all__ = ('NavigationDrawer', )

from kivy.animation import Animation
from kivy.uix.widget import Widget
from kivy.uix.stencilview import StencilView
from kivy.metrics import dp
from kivy.clock import Clock
from kivy.properties import (ObjectProperty, NumericProperty, OptionProperty,
                             BooleanProperty, StringProperty)
from kivy.resources import resource_add_path
from kivy.lang import Builder
import os.path

resource_add_path(os.path.dirname(__file__))

Builder.load_string('''
<NavigationDrawer>:
    size_hint: (1,1)
    _side_panel: sidepanel
    _main_panel: mainpanel
    _join_image: joinimage
    side_panel_width: min(dp(250), 0.5*self.width)
    BoxLayout:
        id: sidepanel
        y: root.y
        x: root.x - \
           (1-root._anim_progress)* \
           root.side_panel_init_offset*root.side_panel_width
        height: root.height
        width: root.side_panel_width
        opacity: root.side_panel_opacity + \
                 (1-root.side_panel_opacity)*root._anim_progress
        canvas:
            Color:
                rgba: (0,0,0,1)
            Rectangle:
                pos: self.pos
                size: self.size
        canvas.after:
            Color:
                rgba: (0,0,0,(1-root._anim_progress)*root.side_panel_darkness)
            Rectangle:
                size: self.size
                pos: self.pos
    BoxLayout:
        id: mainpanel
        x: root.x + \
           root._anim_progress * \
           root.side_panel_width * \
           root.main_panel_final_offset
        y: root.y
        size: root.size
        canvas:
            Color:
                rgba: (0,0,0,1)
            Rectangle:
                pos: self.pos
                size: self.size
        canvas.after:
            Color:
                rgba: (0,0,0,root._anim_progress*root.main_panel_darkness)
            Rectangle:
                size: self.size
                pos: self.pos
    Image:
        id: joinimage
        opacity: min(sidepanel.opacity, 0 if root._anim_progress < 0.00001 \
                 else min(root._anim_progress*40,1))
        source: root._choose_image(root._main_above, root.separator_image)
        mipmap: False
        width: root.separator_image_width
        height: root._side_panel.height
        x: (mainpanel.x - self.width + 1) if root._main_above \
           else (sidepanel.x + sidepanel.width - 1)
        y: root.y
        allow_stretch: True
        keep_ratio: False
''')


class NavigationDrawerException(Exception):
    '''Raised when add_widget or remove_widget called incorrectly on a
    NavigationDrawer.
	升显出来当add_widget 或者 remove_widget 在NavigationDrawer叫唤正确的时候。
	就像三国之虎符,乃一行证。
    '''


class NavigationDrawer(StencilView):
    '''Widget taking two children, a side panel and a main panel,
    displaying them in a way that replicates the popular Android
    functionality. See module documentation for more info.
组件接纳俩子类,一个侧仪表盘 和一个 主仪表盘, 展示它们通过一种方式,一种
复制当下流行的Android功能。看模块文档来获取更多信息。
    '''

    # Internal references for side, main and image widgets
    _side_panel = ObjectProperty()
    _main_panel = ObjectProperty()
    _join_image = ObjectProperty()

    side_panel = ObjectProperty(None, allownone=True)
    '''Automatically bound to whatever widget is added as the hidden panel.
	 自动绑定到组件,无论组件是不是被当作隐藏的仪表盘添加的。
	'''
    
    main_panel = ObjectProperty(None, allownone=True)
    '''Automatically bound to whatever widget is added as the main panel.
		自动绑定到组件,无论组件是不是被当作主仪表盘添加的。
	'''
    

    # Appearance properties	外表属性
    side_panel_width = NumericProperty()
    '''The width of the hidden side panel. Defaults to the minimum of
    250dp or half the NavigationDrawer width.
		隐藏侧仪表盘的宽度。默认是250dp的最小值或者是NavigationDrawer宽度的一半。
	'''
    separator_image = StringProperty('')
    '''The path to an image that will be placed between the side and main
    panels. If set to `''`, defaults to a gradient from black to
    transparent in an appropriate direction (left->right if side panel
    above main, right->left if main panel on top).
	到一个将要被安置在侧仪表盘 和 主仪表盘 之间的图片的路径。 如果设置'',默认到1个斜坡从黑到
	透明的在一个合适的方向(左->右 如果侧仪表盘在主仪表盘之上,  右->左 如果主仪表盘在上。)
	'''
    separator_image_width = NumericProperty(dp(10))
    '''The width of the separator image. Defaults to 10dp
	图片分隔的宽度, 默认10dp
	'''
	
	
    # Touch properties  触摸属性
    ## touch_accept_width
    touch_accept_width = NumericProperty('14dp')
    '''Distance from the left of the NavigationDrawer in which to grab the
    touch and allow revealing of the hidden panel.
	距离从左到NavigationDrawer 在抓取这 触摸点 并且允许展示被隐藏的仪表盘
	'''
	

	## _touch

    _touch = ObjectProperty(None, allownone=True)  # The currently active touch 当前起作用的touch

    # Animation properties   动画属性
    state = OptionProperty('closed', options=('open', 'closed'))
    '''Specifies the state of the widget. Must be one of 'open' or
    'closed'. Setting its value automatically jumps to the relevant state,
    or users may use the anim_to_state() method to animate the
    transition.
	详细说明组件的状态。 其状态 必须是一个"Open" 或者 "close"。 自动地设置它的值跳转到相关的状态
	或者用户可以使用  anim_to_state() 方法来动画这转变。
	'''

	## anim_time 设定动画页面转变所用时间 

    anim_time = NumericProperty(0.3)
    '''The time taken for the panel to slide to the open/closed state when
    released or manually animated with anim_to_state.'''
    min_dist_to_open = NumericProperty(0.7)
    '''Must be between 0 and 1. Specifies the fraction of the hidden panel
    width beyond which the NavigationDrawer will relax to open state when
    released. Defaults to 0.7.
	必须在01之间。 尤其隐藏仪表盘之外的小数宽度, 当释放时,NavifationDrawer将放松到 "open"
	状态。
	搞不太懂,看看文心怎么说:
	

> 这句话是关于Android开发中NavigationDrawer(导航抽屉)的一个属性或行为的描述。NavigationDrawer是Android应用中的一个常见组件,通常用于在屏幕的一侧(如左侧或右侧)提供一个可以滑动的面板,其中包含应用的导航菜单或其他内容。

具体来说,这句话描述的是NavigationDrawer的一个“释放”行为,即当用户触摸并拖动NavigationDrawer(隐藏面板)但随后释放它时,抽屉如何响应。

··  Fraction of the hidden panel width:这指的是隐藏面板(即NavigationDrawer未完全展开时仍被隐藏的部分)的宽度的比例。
··  Beyond which the NavigationDrawer will relax to open state:这意味着当NavigationDrawer被拖动到这个宽度的某个比例(由指定的分数确定)之外时,如果用户释放它,抽屉将“放松”到完全打开的状态。
··  Defaults to 0.7:默认情况下,这个比例是0.7,意味着如果NavigationDrawer被拖动到其隐藏部分宽度的70%以上,然后用户释放它,抽屉将自动滑到完全打开的位置。
这个特性对于提供流畅的用户体验很有用,因为它允许用户通过部分拖动来快速决定是完全打开抽屉还是让它回到关闭状态。如果用户只稍微拖动了一下,抽屉可能不会完全打开,但如果他们拖动得足够远,抽屉就会完全展开。

	'''
    _anim_progress = NumericProperty(0)  # Internal state controlling
                                         # widget positions
    _anim_init_progress = NumericProperty(0)

    # Animation controls  动画控制
    top_panel = OptionProperty('main', options=['main', 'side'])
    '''Denotes which panel should be drawn on top of the other. Must be
    one of 'main' or 'side'. Defaults to 'main'.
		仪表盘应被画在其他玩意儿上面的标志。必须是"main" 或者 "side"中的一个。 默认值是"main"
	'''
    _main_above = BooleanProperty(True)

    side_panel_init_offset = NumericProperty(0.5)
    '''Intial offset (to the left of the widget) of the side panel, in
    units of its total width. Opening the panel moves it smoothly to its
    final position at the left of the screen.
		侧仪表盘的偏离的初始值 (到组件儿的左边), 其单位是基于它的总宽度。打开仪表盘平滑地移动它
		到它左边屏幕的最终位置。
	'''

    side_panel_darkness = NumericProperty(0.8)
    '''Controls the fade-to-black of the side panel in its hidden
    state. Must be between 0 (no fading) and 1 (fades to totally
    black).
	
	'''

    side_panel_opacity = NumericProperty(1)
    '''Controls the opacity of the side panel in its hidden state. Must be
    between 0 (fade to transparent) and 1 (no transparency)'''

    main_panel_final_offset = NumericProperty(1)
    '''Final offset (to the right of the normal position) of the main
    panel, in units of the side panel width.'''

    main_panel_darkness = NumericProperty(0)
    '''Controls the fade-to-black of the main panel when the side panel is
    in its hidden state. Must be between 0 (no fading) and 1 (fades to
    totally black).
    '''

    opening_transition = StringProperty('out_cubic')
    '''The name of the animation transition type to use when animating to
    an open state. Defaults to 'out_cubic'.'''

    closing_transition = StringProperty('in_cubic')
    '''The name of the animation transition type to use when animating to
    a closed state. Defaults to 'out_cubic'.'''

设定动画转变效果 anim_type

anim_type = OptionProperty('reveal_from_below',
                           options=['slide_above_anim',
                                    'slide_above_simple',
                                    'fade_in',
                                    'reveal_below_anim',
                                    'reveal_below_simple',
                                    ])
'''The default animation type to use. Several options are available,
modifying all possibly animation properties including darkness,
opacity, movement and draw height. Users may also (and are
encouaged to) edit these properties individually, for a vastly
larger range of possible animations. Defaults to reveal_below_anim.
'''
默认动画类型来使用。 几种选择是适合的,修改所有可能的动画属性包括
暗度、透明度、动作和抽拉高度。 用户也可以(也激励这样来做)私下地修改这些
属性。
  def __init__(self, **kwargs):
        super(NavigationDrawer, self).__init__(**kwargs)
        Clock.schedule_once(self.on__main_above, 0)

    def on_anim_type(self, *args):
        anim_type = self.anim_type
        if anim_type == 'slide_above_anim':
            self.top_panel = 'side'
            self.side_panel_darkness = 0
            self.side_panel_opacity = 1
            self.main_panel_final_offset = 0.5
            self.main_panel_darkness = 0.5
            self.side_panel_init_offset = 1
        if anim_type == 'slide_above_simple':
            self.top_panel = 'side'
            self.side_panel_darkness = 0
            self.side_panel_opacity = 1
            self.main_panel_final_offset = 0
            self.main_panel_darkness = 0
            self.side_panel_init_offset = 1
        elif anim_type == 'fade_in':
            self.top_panel = 'side'
            self.side_panel_darkness = 0
            self.side_panel_opacity = 0
            self.main_panel_final_offset = 0
            self.main_panel_darkness = 0
            self.side_panel_init_offset = 0.5
        elif anim_type == 'reveal_below_anim':
            self.top_panel = 'main'
            self.side_panel_darkness = 0.8
            self.side_panel_opacity = 1
            self.main_panel_final_offset = 1
            self.main_panel_darkness = 0
            self.side_panel_init_offset = 0.5
        elif anim_type == 'reveal_below_simple':
            self.top_panel = 'main'
            self.side_panel_darkness = 0
            self.side_panel_opacity = 1
            self.main_panel_final_offset = 1
            self.main_panel_darkness = 0
            self.side_panel_init_offset = 0

    def on_top_panel(self, *args):
        if self.top_panel == 'main':
            self._main_above = True
        else:
            self._main_above = False

    def on__main_above(self, *args):
        newval = self._main_above
        main_panel = self._main_panel
        side_panel = self._side_panel
        self.canvas.remove(main_panel.canvas)
        self.canvas.remove(side_panel.canvas)
        if newval:
            self.canvas.insert(0, main_panel.canvas)
            self.canvas.insert(0, side_panel.canvas)
        else:
            self.canvas.insert(0, side_panel.canvas)
            self.canvas.insert(0, main_panel.canvas)

    def toggle_main_above(self, *args):
        if self._main_above:
            self._main_above = False
        else:
            self._main_above = True

    def add_widget(self, widget):
        if len(self.children) == 0:
            super(NavigationDrawer, self).add_widget(widget)
            self._side_panel = widget
        elif len(self.children) == 1:
            super(NavigationDrawer, self).add_widget(widget)
            self._main_panel = widget
        elif len(self.children) == 2:
            super(NavigationDrawer, self).add_widget(widget)
            self._join_image = widget
        elif self.side_panel is None:
            self._side_panel.add_widget(widget)
            self.side_panel = widget
        elif self.main_panel is None:
            self._main_panel.add_widget(widget)
            self.main_panel = widget
        else:
            raise NavigationDrawerException(
                'Can\'t add more than two widgets'
                'directly to NavigationDrawer')

    def remove_widget(self, widget):
        if widget is self.side_panel:
            self._side_panel.remove_widget(widget)
            self.side_panel = None
        elif widget is self.main_panel:
            self._main_panel.remove_widget(widget)
            self.main_panel = None
        else:
            raise NavigationDrawerException(
                'Widget is neither the side or main panel, can\'t remove it.')

    def set_side_panel(self, widget):
        '''Removes any existing side panel widgets, and replaces them with the
        argument `widget`.
        '''
        # Clear existing side panel entries
        if len(self._side_panel.children) > 0:
            for child in self._side_panel.children:
                self._side_panel.remove(child)
        # Set new side panel
        self._side_panel.add_widget(widget)
        self.side_panel = widget

    def set_main_panel(self, widget):
        '''Removes any existing main panel widgets, and replaces them with the
        argument `widget`.
        '''
        # Clear existing side panel entries
        if len(self._main_panel.children) > 0:
            for child in self._main_panel.children:
                self._main_panel.remove_widget(child)
        # Set new side panel
        self._main_panel.add_widget(widget)
        self.main_panel = widget

    def on__anim_progress(self, *args):
        if self._anim_progress > 1:
            self._anim_progress = 1
        elif self._anim_progress < 0:
            self._anim_progress = 0
        if self._anim_progress >= 1:
            self.state = 'open'
        elif self._anim_progress <= 0:
            self.state = 'closed'

    def on_state(self, *args):
        Animation.cancel_all(self)
        if self.state == 'open':
            self._anim_progress = 1
        else:
            self._anim_progress = 0

    def anim_to_state(self, state):
        '''If not already in state `state`, animates smoothly to it, taking
        the time given by self.anim_time. State may be either 'open'
        or 'closed'.

        '''
        if state == 'open':
            anim = Animation(_anim_progress=1,
                             duration=self.anim_time,
                             t=self.closing_transition)
            anim.start(self)
        elif state == 'closed':
            anim = Animation(_anim_progress=0,
                             duration=self.anim_time,
                             t=self.opening_transition)
            anim.start(self)
        else:
            raise NavigationDrawerException(
                'Invalid state received, should be one of `open` or `closed`')
#toggle_state
    def toggle_state(self, animate=True):
        '''Toggles from open to closed or vice versa, optionally animating or
        simply jumping.
			开启到 关闭的转换, 反之代替亦然, 可供选择地动画 或者简单的跳转
		'''
        if self.state == 'open':
            if animate:
                self.anim_to_state('closed')
            else:
                self.state = 'closed'
        elif self.state == 'closed':
            if animate:
                self.anim_to_state('open')
            else:
                self.state = 'open'

    def on_touch_down(self, touch):
        col_self = self.collide_point(*touch.pos)
        col_side = self._side_panel.collide_point(*touch.pos)
        col_main = self._main_panel.collide_point(*touch.pos)

        if self._anim_progress < 0.001:  # i.e. closed
            valid_region = (self.x <=
                            touch.x <=
                            (self.x + self.touch_accept_width))
            if not valid_region:
                self._main_panel.on_touch_down(touch)
                return False
        else:
            if col_side and not self._main_above:
                self._side_panel.on_touch_down(touch)
                return False
            valid_region = (self._main_panel.x <=
                            touch.x <=
                            (self._main_panel.x + self._main_panel.width))
            if not valid_region:
                if self._main_above:
                    if col_main:
                        self._main_panel.on_touch_down(touch)
                    elif col_side:
                        self._side_panel.on_touch_down(touch)
                else:
                    if col_side:
                        self._side_panel.on_touch_down(touch)
                    elif col_main:
                        self._main_panel.on_touch_down(touch)
                return False
        Animation.cancel_all(self)
        self._anim_init_progress = self._anim_progress
        self._touch = touch
        touch.ud['type'] = self.state
        touch.ud['panels_jiggled'] = False  # If user moved panels back
                                            # and forth, don't default
                                            # to close on touch release
        touch.grab(self)
        return True

    def on_touch_move(self, touch):
        if touch is self._touch:
            dx = touch.x - touch.ox
            self._anim_progress = max(0, min(self._anim_init_progress +
                                            (dx / self.side_panel_width), 1))
            if self._anim_progress < 0.975:
                touch.ud['panels_jiggled'] = True
        else:
            super(NavigationDrawer, self).on_touch_move(touch)
            return

    def on_touch_up(self, touch):
        if touch is self._touch:
            self._touch = None
            init_state = touch.ud['type']
            touch.ungrab(self)
            jiggled = touch.ud['panels_jiggled']
            if init_state == 'open' and not jiggled:
                if self._anim_progress >= 0.975:
                        self.anim_to_state('closed')
                else:
                    self._anim_relax()
            else:
                self._anim_relax()
        else:
            super(NavigationDrawer, self).on_touch_up(touch)
            return

    def _anim_relax(self):
        '''Animates to the open or closed position, depending on whether the
        current position is past self.min_dist_to_open.

        '''
        if self._anim_progress > self.min_dist_to_open:
            self.anim_to_state('open')
        else:
            self.anim_to_state('closed')

    def _choose_image(self, *args):
        '''Chooses which image to display as the main/side separator, based on
        _main_above.'''
        if self.separator_image:
            return self.separator_image
        if self._main_above:
            return 'navigationdrawer_gradient_rtol.png'
        else:
            return 'navigationdrawer_gradient_ltor.png'

if __name__ == '__main__':
    from kivy.base import runTouchApp
    from kivy.uix.boxlayout import BoxLayout
    from kivy.uix.label import Label
    from kivy.uix.button import Button
    from kivy.uix.popup import Popup
    from kivy.uix.image import Image
    from kivy.core.window import Window

    navigationdrawer = NavigationDrawer()

    side_panel = BoxLayout(orientation='vertical')
    side_panel.add_widget(Label(text='Panel label'))
    popup = Popup(title='Sidebar popup',
                  content=Label(
                      text='You clicked the sidebar\npopup button'),
                  size_hint=(0.7, 0.7))
    first_button = Button(text='Popup\nbutton')
    first_button.bind(on_release=popup.open)
    side_panel.add_widget(first_button)
    side_panel.add_widget(Button(text='Another\nbutton'))
    navigationdrawer.add_widget(side_panel)

    label_head = (
        '[b]Example label filling main panel[/b]\n\n[color=ff0000](p'
        'ull from left to right!)[/color]\n\nIn this example, the le'
        'ft panel is a simple boxlayout menu, and this main panel is'
        ' a BoxLayout with a label and example image.\n\nSeveral pre'
        'set layouts are available (see buttons below), but users ma'
        'y edit every parameter for much more customisation.')
    main_panel = BoxLayout(orientation='vertical')
    label_bl = BoxLayout(orientation='horizontal')
    label = Label(text=label_head, font_size='15sp',
                  markup=True, valign='top')
    label_bl.add_widget(Widget(size_hint_x=None, width=dp(10)))
    label_bl.add_widget(label)
    label_bl.add_widget(Widget(size_hint_x=None, width=dp(10)))
    main_panel.add_widget(Widget(size_hint_y=None, height=dp(10)))
    main_panel.add_widget(label_bl)
    main_panel.add_widget(Widget(size_hint_y=None, height=dp(10)))
    navigationdrawer.add_widget(main_panel)
    label.bind(size=label.setter('text_size'))

    def set_anim_type(name):
        navigationdrawer.anim_type = name

    def set_transition(name):
        navigationdrawer.opening_transition = name
        navigationdrawer.closing_transition = name

    modes_layout = BoxLayout(orientation='horizontal')
    modes_layout.add_widget(Label(text='preset\nanims:'))
    slide_an = Button(text='slide_\nabove_\nanim')
    slide_an.bind(on_press=lambda j: set_anim_type('slide_above_anim'))
    slide_sim = Button(text='slide_\nabove_\nsimple')
    slide_sim.bind(on_press=lambda j: set_anim_type('slide_above_simple'))
    fade_in_button = Button(text='fade_in')
    fade_in_button.bind(on_press=lambda j: set_anim_type('fade_in'))
    reveal_button = Button(text='reveal_\nbelow_\nanim')
    reveal_button.bind(on_press=
                       lambda j: set_anim_type('reveal_below_anim'))
    slide_button = Button(text='reveal_\nbelow_\nsimple')
    slide_button.bind(on_press=
                      lambda j: set_anim_type('reveal_below_simple'))
    modes_layout.add_widget(slide_an)
    modes_layout.add_widget(slide_sim)
    modes_layout.add_widget(fade_in_button)
    modes_layout.add_widget(reveal_button)
    modes_layout.add_widget(slide_button)
    main_panel.add_widget(modes_layout)

    transitions_layout = BoxLayout(orientation='horizontal')
    transitions_layout.add_widget(Label(text='anim\ntransitions'))
    out_cubic = Button(text='out_cubic')
    out_cubic.bind(on_press=
                   lambda j: set_transition('out_cubic'))
    in_quint = Button(text='in_quint')
    in_quint.bind(on_press=
                  lambda j: set_transition('in_quint'))
    linear = Button(text='linear')
    linear.bind(on_press=
                lambda j: set_transition('linear'))
    out_sine = Button(text='out_sine')
    out_sine.bind(on_press=
                  lambda j: set_transition('out_sine'))
    transitions_layout.add_widget(out_cubic)
    transitions_layout.add_widget(in_quint)
    transitions_layout.add_widget(linear)
    transitions_layout.add_widget(out_sine)
    main_panel.add_widget(transitions_layout)

    button = Button(text='toggle NavigationDrawer state (animate)',
                    size_hint_y=0.2)
    button.bind(on_press=lambda j: navigationdrawer.toggle_state())
    button2 = Button(text='toggle NavigationDrawer state (jump)',
                     size_hint_y=0.2)
    button2.bind(on_press=lambda j: navigationdrawer.toggle_state(False))
    button3 = Button(text='toggle _main_above', size_hint_y=0.2)
    button3.bind(on_press=navigationdrawer.toggle_main_above)
    main_panel.add_widget(button)
    main_panel.add_widget(button2)
    main_panel.add_widget(button3)

    Window.add_widget(navigationdrawer)

    runTouchApp()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xinzheng新政

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值