25
25
NumericProperty ,
26
26
ObjectProperty ,
27
27
StringProperty ,
28
+ BooleanProperty
28
29
)
29
30
from kivy .uix .behaviors import ButtonBehavior
30
31
from kivy .uix .boxlayout import BoxLayout
34
35
35
36
from kivymd import uix_path
36
37
from kivymd .font_definitions import theme_font_styles
37
- from kivymd .uix .behaviors import StencilBehavior
38
38
from kivymd .uix .boxlayout import MDBoxLayout
39
39
from kivymd .uix .label import MDIcon
40
+ from kivymd .utils import next_frame
40
41
41
42
with open (
42
43
os .path .join (uix_path , "search" , "search.kv" ), encoding = "utf-8"
@@ -72,104 +73,145 @@ class MDSearchViewLeadingContainer(BoxLayout):
72
73
pass
73
74
74
75
75
- class MDSearchViewContainer (StencilBehavior , BoxLayout ):
76
+ class MDSearchViewContainer (BoxLayout ):
76
77
pass
77
78
78
79
79
80
class MDSearchWidget (RelativeLayout ):
80
81
81
82
_font_style = theme_font_styles ["Title" ]["medium" ]
82
- _duration = 0.4
83
- _transition = "in_out_circ"
84
- state = "closed "
83
+ _d = 0.4
84
+ _t = "in_out_circ"
85
+ state = "close "
85
86
86
87
def __init__ (self , root , * args , ** kwargs ):
87
88
super ().__init__ (* args , ** kwargs )
88
89
self .root = root
89
90
90
- def update_pos (self , * args ):
91
- self .ids .root_container .pos = self .root .pos
91
+ def update_bar (self , * args ):
92
+ if self .state == "close" :
93
+ self .ids .root_container .size = self .root .size
94
+ self .ids .root_container .radius = dp (28 )
95
+ self .ids .root_container .pos = self .root .pos
96
+ else :
97
+ if self .root .docked :
98
+ self .ids .root_container .radius = [dp (28 )] * 4
99
+ docked_size = self .root .width , dp (56 ) + self .root .docked_height
100
+ self .ids .root_container .pos = [
101
+ self .root .pos [0 ], self .root .pos [1 ] - docked_size [1 ] + dp (56 )
102
+ ]
103
+ else :
104
+ self .ids .root_container .radius = [0 ] * 4
105
+ self .ids .root_container .pos = [0 ,0 ]
106
+ self .ids .root_container .size = self .size
107
+
108
+ def _docked_open (self , opacity_down , opacity_up ):
109
+ docked_size = self .root .width , dp (56 ) + self .root .docked_height
110
+ Animation (
111
+ size = docked_size ,
112
+ pos = [self .root .pos [0 ], self .root .pos [1 ] - docked_size [1 ] + dp (56 )],
113
+ radius = [dp (28 )] * 4 ,
114
+ t = self ._t ,
115
+ d = self ._d ,
116
+ ).start (self .ids .root_container )
117
+ self .root ._view_container .size_hint_y = 1
118
+ self .root ._view_container .opacity = 0
119
+ self .root ._view_container .padding = [0 , 0 , 0 , dp (16 )]
120
+ next_frame (
121
+ self .ids .root_container .add_widget ,
122
+ self .root ._view_container ,
123
+ index = 1 ,
124
+ t = self ._d ,
125
+ )
126
+ next_frame (opacity_up .start , self .root ._view_container , t = self ._d )
127
+ self .icons_open (opacity_up , opacity_down , self ._d / 2 )
92
128
93
- def update_size (self , * args ):
94
- self .ids .root_container .size = self .root .size
95
- self .ids .root_container .radius = dp (28 )
129
+ def _docked_close (self , opacity_down , opacity_up ):
130
+ self ._close (opacity_down , opacity_up )
96
131
97
- def _delayed_run (self , delay , func , * args ):
98
- Clock . schedule_once ( lambda dt : func ( * args ), delay )
132
+ def _open (self , opacity_down , opacity_up ):
133
+ h_d = self . _d / 2
99
134
100
- def _open ( self , d , t , opacity_down , opacity_up , docked ):
135
+ # container
101
136
self .root ._view_container .size_hint_y = 1
102
137
self .root ._view_container .opacity = 0
138
+ self .root ._view_container .padding = [0 ] * 4
103
139
self .ids .root_container .add_widget (self .root ._view_container , index = 1 )
104
- self ._delayed_run (d / 4 , opacity_up .start , self .root ._view_container )
105
- Animation (size = self .size , pos = self .pos , radius = [0 ] * 4 , t = t , d = d ).start (
106
- self .ids .root_container
107
- )
108
- Animation (height = dp (70 ), t = t , d = d ).start (self .ids .header )
109
- opacity_down .start (self .root ._bar_trailing_container )
110
- opacity_down .start (self .root ._bar_leading_container )
111
- self .root ._view_leading_container .opacity = 0
112
- self .root ._view_trailing_container .opacity = 0
113
- self ._delayed_run (d / 2 , self .update_state_opened )
114
- self ._delayed_run (
115
- d / 2 , opacity_up .start , self .root ._view_trailing_container
116
- )
117
- self ._delayed_run (
118
- d / 2 , opacity_up .start , self .root ._view_leading_container
119
- )
140
+ next_frame (opacity_up .start , self .root ._view_container , t = h_d / 2 )
141
+ Animation (
142
+ size = self .size , pos = self .pos , radius = [0 ] * 4 , t = self ._t , d = self ._d
143
+ ).start (self .ids .root_container )
120
144
121
- def _close (self , d , t , opacity_down , opacity_up , docked ):
145
+ # header
146
+ Animation (height = dp (70 ), t = self ._t , d = self ._d ).start (self .ids .header )
147
+ self .icons_open (opacity_up , opacity_down , h_d )
148
+
149
+ def _close (self , opacity_down , opacity_up ):
150
+ h_d = self ._d / 2
151
+ # container
122
152
self .root ._view_container .size_hint_y = None
123
153
self .root ._view_container .opacity = 1
124
154
opacity_down .start (self .root ._view_container )
125
155
if self .root ._view_container in self .ids .root_container .children :
126
- self ._delayed_run (
127
- d / 2 ,
156
+ next_frame (
128
157
self .ids .root_container .remove_widget ,
129
158
self .root ._view_container ,
159
+ t = h_d ,
130
160
)
131
- self ._delayed_run (
132
- d , setattr , self .root ._view_container , "height" , dp (55 )
133
- )
161
+ next_frame (setattr , self .root ._view_container , "height" , dp (55 ), t = h_d )
134
162
Animation (
135
163
size = [self .root .width , dp (56 )],
136
164
pos = self .root .pos ,
137
165
radius = [dp (28 )] * 4 ,
138
- t = t ,
139
- d = d ,
166
+ t = self . _t ,
167
+ d = self . _d ,
140
168
).start (self .ids .root_container )
141
- Animation (height = dp (56 ), t = t , d = d ).start (self .ids .header )
169
+
170
+ # header
171
+ Animation (height = dp (56 ), t = self ._t , d = self ._d ).start (self .ids .header )
172
+ self .icons_close (opacity_up , opacity_down , h_d )
173
+
174
+ def icons_close (self , opacity_up , opacity_down , h_d ):
142
175
opacity_down .start (self .root ._view_trailing_container )
143
176
opacity_down .start (self .root ._view_leading_container )
144
177
self .root ._bar_leading_container .opacity = 0
145
178
self .root ._bar_trailing_container .opacity = 0
146
- self ._delayed_run (d / 2 , self .update_state_closed )
147
- self ._delayed_run (
148
- d / 2 , opacity_up .start , self .root ._bar_trailing_container
149
- )
150
- self ._delayed_run (
151
- d / 2 , opacity_up .start , self .root ._bar_leading_container
152
- )
179
+ next_frame (self .update_state_closed , t = h_d )
180
+ next_frame (opacity_up .start , self .root ._bar_trailing_container , t = h_d )
181
+ next_frame (opacity_up .start , self .root ._bar_leading_container , t = h_d )
182
+
183
+ def icons_open (self , opacity_up , opacity_down , h_d ):
184
+ opacity_down .start (self .root ._bar_trailing_container )
185
+ opacity_down .start (self .root ._bar_leading_container )
186
+ self .root ._view_leading_container .opacity = 0
187
+ self .root ._view_trailing_container .opacity = 0
188
+ next_frame (self .update_state_opened , t = h_d )
189
+ next_frame (opacity_up .start , self .root ._view_trailing_container , t = h_d )
190
+ next_frame (opacity_up .start , self .root ._view_leading_container , t = h_d )
153
191
154
192
switching_state = False
155
193
156
194
def switch_state (self , new_state ):
157
195
if self .switching_state or new_state == self .state :
158
196
return
159
197
self .switching_state = True
160
- docked = False
161
- opacity_down = Animation (
162
- opacity = 0 , t = self ._transition , d = self ._duration / 2
163
- )
164
- opacity_up = Animation (
165
- opacity = 1 , t = self ._transition , d = self ._duration / 2
166
- )
167
198
168
- getattr (self , "_" + new_state )(
169
- self ._duration , self ._transition , opacity_down , opacity_up , docked
170
- )
199
+ opacity_down = Animation (opacity = 0 , t = self ._t , d = self ._d / 2 )
200
+ opacity_up = Animation (opacity = 1 , t = self ._t , d = self ._d / 2 )
201
+
202
+ if self .root .docked :
203
+ self .root .width = self .root .docked_width
204
+ self .ids .root_container .width = self .root .docked_width
205
+ getattr (self , "_docked_" + new_state )(opacity_down , opacity_up )
206
+ else :
207
+ getattr (self , "_" + new_state )(opacity_down , opacity_up )
208
+
209
+ if new_state == "close" :
210
+ self .ids .text_input .focus = False
211
+
212
+ self .state = new_state
171
213
Clock .schedule_once (
172
- lambda dt : setattr (self , "switching_state" , False ), self ._duration
214
+ lambda dt : setattr (self , "switching_state" , False ), self ._d
173
215
)
174
216
175
217
def init_state (self ):
@@ -181,6 +223,11 @@ def clean_header(self):
181
223
self .ids .header .remove_widget (child )
182
224
183
225
def init_state (self ):
226
+ if self .root .docked :
227
+ self .root .size_hint_x = None
228
+ self .root .width = self .root .docked_width
229
+ else :
230
+ self .root .size_hint_x = 1
184
231
self .ids .root_container .size = [self .root .width , dp (56 )]
185
232
self .update_state_closed ()
186
233
@@ -200,6 +247,9 @@ class MDSearchBar(Widget):
200
247
leading_icon = StringProperty ("magnify" )
201
248
supporting_text = StringProperty ("Hinted search text" )
202
249
view_root = ObjectProperty (None )
250
+ docked_width = NumericProperty (dp (360 ))
251
+ docked_height = NumericProperty (dp (240 ))
252
+ docked = BooleanProperty (False )
203
253
204
254
# internal props
205
255
_search_widget = None
@@ -219,8 +269,16 @@ class MDSearchBar(Widget):
219
269
def __init__ (self , * args , ** kwargs ):
220
270
super ().__init__ (* args , ** kwargs )
221
271
self ._search_widget = MDSearchWidget (self )
222
- self .bind (pos = self ._search_widget .update_pos )
223
- self .bind (size = self ._search_widget .update_size )
272
+ self .bind (pos = self ._search_widget .update_bar )
273
+ self .bind (size = self ._search_widget .update_bar )
274
+ self .on_docked (self , self .docked )
275
+
276
+ def on_docked (self , instance , docked ):
277
+ if docked :
278
+ self .size_hint_x = None
279
+ self .width = self .docked_width
280
+ else :
281
+ self .size_hint_x = 1
224
282
225
283
def on_supporting_text (self , instance , text ):
226
284
self ._search_widget .ids .text_input .hint_text = text
@@ -230,6 +288,8 @@ def on_view_root(self, *args):
230
288
self ._search_widget .parent .remove_widget (self ._search_widget )
231
289
self .view_root .add_widget (self ._search_widget )
232
290
self ._search_widget .init_state ()
291
+ self ._search_widget .update_bar ()
292
+ self .view_root .bind (size = self ._search_widget .update_bar )
233
293
234
294
def add_widget (self , widget ):
235
295
if widget .__class__ .__name__ in self ._view_map .keys ():
0 commit comments