DrawerLayout.cs (20856B)
1 using System; 2 using System.Linq; 3 using System.Windows; 4 using Windows.Foundation; 5 using Windows.UI; 6 using Windows.UI.Xaml; 7 using Windows.UI.Xaml.Controls; 8 using Windows.UI.Xaml.Input; 9 using Windows.UI.Xaml.Media; 10 using Windows.UI.Xaml.Media.Animation; 11 12 namespace File360 13 { 14 public class DrawerLayout : Grid 15 { 16 #region Globals and events 17 private readonly PropertyPath _translatePath = new PropertyPath("(UIElement.RenderTransform).(TranslateTransform.X)"); 18 private readonly PropertyPath _colorPath = new PropertyPath("(Grid.Background).(SolidColorBrush.Color)"); 19 20 private readonly TranslateTransform _listFragmentTransform = new TranslateTransform(); 21 private readonly TranslateTransform _deltaTransform = new TranslateTransform(); 22 private const int MaxAlpha = 190; 23 24 public delegate void DrawerEventHandler(object sender); 25 public event DrawerEventHandler DrawerOpened; 26 public event DrawerEventHandler DrawerClosed; 27 28 private Storyboard _fadeInStoryboard; 29 private Storyboard _fadeOutStoryboard; 30 private Grid _listFragment; 31 private Grid _mainFragment; 32 private Grid _shadowFragment; 33 private double grabCornerLeft = 40; 34 #endregion 35 36 #region Properties 37 38 public bool IsDrawerOpen { get; set; } 39 private PropertyPath TranslatePath 40 { 41 get { return _translatePath; } 42 } 43 private PropertyPath ColorPath 44 { 45 get { return _colorPath; } 46 } 47 48 #endregion 49 50 #region Methods 51 52 public DrawerLayout() 53 { 54 IsDrawerOpen = false; 55 } 56 57 public void InitializeDrawerLayout() 58 { 59 if (Children == null) return; 60 if (Children.Count < 2) return; 61 62 try 63 { 64 _mainFragment = Children.OfType<Grid>().ElementAt(1); 65 _listFragment = Children.OfType<Grid>().ElementAt(2); 66 } 67 catch (Exception) 68 { 69 //ShowStatus(ex.Message); 70 return; 71 } 72 73 if (_mainFragment == null || _listFragment == null) return; 74 75 _mainFragment.Name = "_mainFragment"; 76 _listFragment.Name = "_listFragment"; 77 78 // _mainFragment 79 _mainFragment.HorizontalAlignment = HorizontalAlignment.Left; 80 _mainFragment.VerticalAlignment = VerticalAlignment.Stretch; 81 82 // Render transform _listFragment 83 _listFragment.HorizontalAlignment = HorizontalAlignment.Left; 84 _listFragment.VerticalAlignment = VerticalAlignment.Stretch; 85 _listFragment.Width = Window.Current.Bounds.Width > Window.Current.Bounds.Height ? (Window.Current.Bounds.Height * 2) / 3 : (Window.Current.Bounds.Width * 2) / 3; 86 if (_listFragment.Background == null) _listFragment.Background = new SolidColorBrush(Color.FromArgb(40, 46, 46, 46)); 87 88 var animatedTranslateTransform = new TranslateTransform { X = -_listFragment.Width - 200, Y = 0 }; 89 90 _listFragment.RenderTransform = animatedTranslateTransform; 91 _listFragment.RenderTransformOrigin = new Point(0.5, 0.5); 92 93 _listFragment.UpdateLayout(); 94 95 96 // Create a shadow element 97 _shadowFragment = new Grid 98 { 99 Name = "_shadowFragment", 100 Background = new SolidColorBrush(Color.FromArgb(0, 255, 255, 255)), 101 HorizontalAlignment = HorizontalAlignment.Stretch, 102 VerticalAlignment = VerticalAlignment.Stretch, 103 Visibility = Visibility.Collapsed 104 }; 105 106 // Set ZIndexes 107 Canvas.SetZIndex(_shadowFragment, 49); 108 Canvas.SetZIndex(_listFragment, 51); 109 Children.Add(_shadowFragment); 110 111 // Create a new fadeIn animation storyboard 112 _fadeInStoryboard = new Storyboard(); 113 114 // New double animation 115 var doubleAnimation1 = new DoubleAnimation 116 { 117 Duration = new Duration(new TimeSpan(0, 0, 0, 0, 200)), 118 To = 0 119 }; 120 121 Storyboard.SetTarget(doubleAnimation1, _listFragment); 122 Storyboard.SetTargetProperty(doubleAnimation1, TranslatePath.Path); 123 _fadeInStoryboard.Children.Add(doubleAnimation1); 124 125 // New color animation for _shadowFragment 126 var colorAnimation1 = new ColorAnimation 127 { 128 Duration = new Duration(new TimeSpan(0, 0, 0, 0, 200)), 129 To = Color.FromArgb(190, 0, 0, 0) 130 }; 131 132 Storyboard.SetTarget(colorAnimation1, _shadowFragment); 133 Storyboard.SetTargetProperty(colorAnimation1, ColorPath.Path); 134 _fadeInStoryboard.Children.Add(colorAnimation1); 135 136 // Create a new fadeOut animation storyboard 137 _fadeOutStoryboard = new Storyboard(); 138 139 // New double animation 140 var doubleAnimation2 = new DoubleAnimation 141 { 142 Duration = new Duration(new TimeSpan(0, 0, 0, 0, 200)), 143 To = -_listFragment.Width - 200 144 }; 145 146 Storyboard.SetTarget(doubleAnimation2, _listFragment); 147 Storyboard.SetTargetProperty(doubleAnimation2, TranslatePath.Path); 148 _fadeOutStoryboard.Children.Add(doubleAnimation2); 149 150 // New color animation for _shadowFragment 151 var colorAnimation2 = new ColorAnimation 152 { 153 Duration = new Duration(new TimeSpan(0, 0, 0, 0, 200)), 154 To = Color.FromArgb(0, 0, 0, 0) 155 }; 156 157 Storyboard.SetTarget(colorAnimation2, _shadowFragment); 158 Storyboard.SetTargetProperty(colorAnimation2, ColorPath.Path); 159 _fadeOutStoryboard.Children.Add(colorAnimation2); 160 161 162 _mainFragment.ManipulationMode = ManipulationModes.TranslateX; 163 _mainFragment.ManipulationStarted += mainFragment_ManipulationStarted; 164 165 _listFragment.ManipulationMode = ManipulationModes.TranslateX; 166 _listFragment.ManipulationStarted += listFragment_ManipulationStarted; 167 168 _shadowFragment.ManipulationMode = ManipulationModes.TranslateX; 169 _shadowFragment.ManipulationStarted += shadowFragment_ManipulationStarted; 170 171 _shadowFragment.Tapped += shadowFragment_Tapped; 172 173 } 174 175 176 public void OpenDrawer() 177 { 178 if (_fadeInStoryboard == null || _mainFragment == null || _listFragment == null) return; 179 _shadowFragment.Visibility = Visibility.Visible; 180 _shadowFragment.IsHitTestVisible = true; 181 _fadeInStoryboard.Begin(); 182 IsDrawerOpen = true; 183 184 if (DrawerOpened != null) 185 DrawerOpened(this); 186 } 187 public void CloseDrawer() 188 { 189 if (_fadeOutStoryboard == null || _mainFragment == null || _listFragment == null) return; 190 _fadeOutStoryboard.Begin(); 191 _fadeOutStoryboard.Completed += fadeOutStoryboard_Completed; 192 IsDrawerOpen = false; 193 194 if (DrawerClosed != null) 195 DrawerClosed(this); 196 } 197 private void shadow_Completed(object sender, object e) 198 { 199 _shadowFragment.IsHitTestVisible = false; 200 _shadowFragment.Visibility = Visibility.Collapsed; 201 IsDrawerOpen = false; 202 203 // raise close event 204 if (DrawerClosed != null) DrawerClosed(this); 205 } 206 private void fadeOutStoryboard_Completed(object sender, object e) 207 { 208 _shadowFragment.Visibility = Visibility.Collapsed; 209 IsDrawerOpen = false; 210 if (DrawerClosed != null) DrawerClosed(this); 211 } 212 private void MoveListFragment(double left, Color color) 213 { 214 var s = new Storyboard(); 215 216 var doubleAnimation = new DoubleAnimation 217 { 218 Duration = new Duration(new TimeSpan(0, 0, 0, 0, 200)), 219 To = left 220 }; 221 222 Storyboard.SetTarget(doubleAnimation, _listFragment); 223 Storyboard.SetTargetProperty(doubleAnimation, TranslatePath.Path); 224 s.Children.Add(doubleAnimation); 225 226 var colorAnimation = new ColorAnimation { Duration = new Duration(new TimeSpan(0, 0, 0, 0, 200)), To = color }; 227 228 Storyboard.SetTarget(colorAnimation, _shadowFragment); 229 Storyboard.SetTargetProperty(colorAnimation, ColorPath.Path); 230 s.Children.Add(colorAnimation); 231 232 s.Begin(); 233 } 234 private void FadeShadowFragment(double left) 235 { 236 // Show shadow fragment 237 _shadowFragment.Background = new SolidColorBrush(Color.FromArgb(255, 255, 255, 255)); 238 _shadowFragment.Visibility = Visibility.Visible; 239 240 // Set bg color based on current _listFragment position. 241 var maxLeft = _listFragment.ActualWidth; 242 var currentLeft = maxLeft - left; 243 244 var temp = Convert.ToInt32((currentLeft / maxLeft) * MaxAlpha); 245 246 // Limit temp variable to 190 to avoid OverflowException 247 if (temp > MaxAlpha) temp = MaxAlpha; 248 249 byte alphaColorIndex; 250 try 251 { 252 alphaColorIndex = Convert.ToByte(MaxAlpha - temp); 253 } 254 catch 255 { 256 alphaColorIndex = 0; 257 } 258 259 _shadowFragment.Background = new SolidColorBrush(Color.FromArgb(alphaColorIndex, 0, 0, 0)); 260 } 261 262 #endregion 263 264 265 #region Main fragment manipulation events 266 267 private void mainFragment_ManipulationStarted(object sender, ManipulationStartedRoutedEventArgs e) 268 { 269 // If the user has the first touch on the left side of canvas, that means he's trying to swipe the drawer 270 if (e.Position.X <= grabCornerLeft) 271 { 272 //Manipulation can be allowed 273 _mainFragment.ManipulationDelta += mainFragment_ManipulationDelta; 274 _mainFragment.ManipulationCompleted += mainFragment_ManipulationCompleted; 275 } 276 } 277 private void mainFragment_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e) 278 { 279 if (Math.Abs(e.Cumulative.Translation.X) > 0 && e.Cumulative.Translation.X <= _listFragment.Width) 280 { 281 _deltaTransform.X = -_listFragment.Width + e.Cumulative.Translation.X; 282 _listFragment.RenderTransform = _deltaTransform; 283 FadeShadowFragment(e.Cumulative.Translation.X); 284 //ShowStatus(e.Cumulative.Translation.X.ToString()); 285 } 286 //if () 287 //{ 288 // //mainFragment_ManipulationCompleted(this, null); 289 // return; 290 //} 291 292 } 293 private void mainFragment_ManipulationCompleted(object sender, ManipulationCompletedRoutedEventArgs e) 294 { 295 // Get left of _listFragment 296 var transform = (TranslateTransform)_listFragment.RenderTransform; 297 if (transform == null) return; 298 var left = transform.X; 299 300 // Set snap divider to 1/20 of _mainFragment width 301 var snapLimit = _mainFragment.ActualWidth / 20; 302 303 // Get init position of _listFragment 304 var initialPosition = -_listFragment.Width; 305 306 // If current left coordinate is smaller than snap limit, close drawer 307 if (Math.Abs(initialPosition - left) < snapLimit + 50) 308 { 309 MoveListFragment(initialPosition, Color.FromArgb(0, 0, 0, 0)); 310 _shadowFragment.Visibility = Visibility.Collapsed; 311 _shadowFragment.IsHitTestVisible = false; 312 313 _mainFragment.ManipulationDelta -= mainFragment_ManipulationDelta; 314 _mainFragment.ManipulationCompleted -= mainFragment_ManipulationCompleted; 315 IsDrawerOpen = false; 316 317 // raise DrawerClosed event 318 if (DrawerClosed != null) DrawerClosed(this); 319 } 320 // else open drawer 321 else if (Math.Abs(initialPosition - left) > snapLimit) 322 { 323 // move drawer to zero 324 MoveListFragment(0, Color.FromArgb(190, 0, 0, 0)); 325 _shadowFragment.Visibility = Visibility.Visible; 326 _shadowFragment.IsHitTestVisible = true; 327 _mainFragment.ManipulationDelta -= mainFragment_ManipulationDelta; 328 _mainFragment.ManipulationCompleted -= mainFragment_ManipulationCompleted; 329 IsDrawerOpen = true; 330 331 // raise DrawerClosed event 332 if (DrawerOpened != null) DrawerOpened(this); 333 } 334 } 335 336 #endregion 337 338 #region List Fragment manipulation events 339 340 private void listFragment_ManipulationStarted(object sender, ManipulationStartedRoutedEventArgs e) 341 { 342 var listWidth = _listFragment.Width; 343 if (e.Position.X >= listWidth) return; 344 _listFragment.ManipulationDelta += listFragment_ManipulationDelta; 345 _listFragment.ManipulationCompleted += listFragment_ManipulationCompleted; 346 } 347 private void listFragment_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e) 348 { 349 if (e.Cumulative.Translation.X <= -_listFragment.Width) 350 { 351 listFragment_ManipulationCompleted(this, null); 352 return; 353 } 354 else if (_listFragmentTransform.X >= 0 && e.Delta.Translation.X > 0) 355 { 356 listFragment_ManipulationCompleted(this, null); 357 return; 358 } 359 _listFragmentTransform.X = e.Cumulative.Translation.X; 360 _listFragment.RenderTransform = _listFragmentTransform; 361 FadeShadowFragment(e.Cumulative.Translation.X + _listFragment.Width); 362 } 363 private void listFragment_ManipulationCompleted(object sender, ManipulationCompletedRoutedEventArgs e) 364 { 365 // Get left of _listFragment 366 var transform = (TranslateTransform)_listFragment.RenderTransform; 367 if (transform == null) return; 368 var left = transform.X; 369 370 // Set snap divider to 1/4 of _mainFragment height 371 var snapLimit = _mainFragment.ActualHeight / 4; 372 373 // Get init position of _listFragment 374 const int initialPosition = 0; 375 376 // If current left coordinate is smaller than snap limit, close drawer 377 if (Math.Abs(initialPosition - left) > snapLimit) 378 { 379 MoveListFragment(-_listFragment.Width, Color.FromArgb(0, 0, 0, 0)); 380 _shadowFragment.Visibility = Visibility.Collapsed; 381 _shadowFragment.IsHitTestVisible = false; 382 _shadowFragment.ManipulationDelta -= listFragment_ManipulationDelta; 383 384 _listFragment.ManipulationDelta -= listFragment_ManipulationDelta; 385 _listFragment.ManipulationCompleted -= listFragment_ManipulationCompleted; 386 IsDrawerOpen = false; 387 388 // raise DrawerClosed event 389 if (DrawerClosed != null) DrawerClosed(this); 390 } 391 // else open drawer 392 else if (Math.Abs(initialPosition - left) < snapLimit) 393 { 394 // move drawer to zero 395 MoveListFragment(0, Color.FromArgb(190, 0, 0, 0)); 396 _shadowFragment.Visibility = Visibility.Visible; 397 _shadowFragment.IsHitTestVisible = true; 398 _shadowFragment.ManipulationDelta += listFragment_ManipulationDelta; 399 400 _listFragment.ManipulationDelta -= listFragment_ManipulationDelta; 401 _listFragment.ManipulationCompleted -= listFragment_ManipulationCompleted; 402 IsDrawerOpen = true; 403 404 // raise Drawer_Open event 405 if (DrawerOpened != null) DrawerOpened(this); 406 } 407 } 408 409 #endregion 410 #region Shadow fragment manipulation events 411 private void shadowFragment_ManipulationStarted(object sender, ManipulationStartedRoutedEventArgs e) 412 { 413 if (e.Cumulative.Translation.X > 0) return; 414 _shadowFragment.ManipulationDelta += _shadowFragment_ManipulationDelta; 415 _shadowFragment.ManipulationCompleted += _shadowFragment_ManipulationCompleted; 416 } 417 418 private void _shadowFragment_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e) 419 { 420 if (e.Cumulative.Translation.X <= -_listFragment.Width) 421 { 422 _shadowFragment_ManipulationCompleted(this, null); 423 return; 424 } 425 else if (_listFragmentTransform.X >= 0 && e.Delta.Translation.X > 0) 426 { 427 _shadowFragment_ManipulationCompleted(this, null); 428 return; 429 } 430 _listFragmentTransform.X = e.Cumulative.Translation.X; 431 _listFragment.RenderTransform = _listFragmentTransform; 432 FadeShadowFragment(e.Cumulative.Translation.X + _listFragment.Width); 433 434 } 435 private void _shadowFragment_ManipulationCompleted(object sender, ManipulationCompletedRoutedEventArgs e) 436 { 437 // Get left of _listFragment 438 var transform = (TranslateTransform)_listFragment.RenderTransform; 439 if (transform == null) return; 440 var left = transform.X; 441 442 // Set snap divider to 1/4 of _mainFragment height 443 var snapLimit = _mainFragment.ActualHeight / 4; 444 445 // Get init position of _listFragment 446 const int initialPosition = 0; 447 448 // If current left coordinate is smaller than snap limit, close drawer 449 if (Math.Abs(initialPosition - left) > snapLimit) 450 { 451 MoveListFragment(-_listFragment.Width, Color.FromArgb(0, 0, 0, 0)); 452 453 _shadowFragment.Visibility = Visibility.Collapsed; 454 _shadowFragment.IsHitTestVisible = false; 455 _shadowFragment.ManipulationDelta -= _shadowFragment_ManipulationDelta; 456 _shadowFragment.ManipulationCompleted -= _shadowFragment_ManipulationCompleted; 457 458 _listFragment.ManipulationDelta -= listFragment_ManipulationDelta; 459 _listFragment.ManipulationCompleted -= listFragment_ManipulationCompleted; 460 461 IsDrawerOpen = false; 462 463 // raise DrawerClosed event 464 if (DrawerClosed != null) DrawerClosed(this); 465 } 466 // else open drawer 467 else if (Math.Abs(initialPosition - left) < snapLimit) 468 { 469 // move drawer to zero 470 MoveListFragment(0, Color.FromArgb(190, 0, 0, 0)); 471 472 _shadowFragment.Visibility = Visibility.Visible; 473 _shadowFragment.IsHitTestVisible = true; 474 _shadowFragment.ManipulationDelta -= _shadowFragment_ManipulationDelta; 475 _shadowFragment.ManipulationCompleted -= _shadowFragment_ManipulationCompleted; 476 477 _listFragment.ManipulationDelta -= listFragment_ManipulationDelta; 478 _listFragment.ManipulationCompleted -= listFragment_ManipulationCompleted; 479 480 IsDrawerOpen = true; 481 482 // raise Drawer_Open event 483 if (DrawerOpened != null) DrawerOpened(this); 484 } 485 } 486 487 private void shadowFragment_Tapped(object sender, TappedRoutedEventArgs e) 488 { 489 var shadow = new Storyboard(); 490 491 var doubleAnimation = new DoubleAnimation 492 { 493 Duration = new Duration(new TimeSpan(0, 0, 0, 0, 200)), 494 To = -_listFragment.Width - 200 495 }; 496 497 Storyboard.SetTarget(doubleAnimation, _listFragment); 498 Storyboard.SetTargetProperty(doubleAnimation, TranslatePath.Path); 499 shadow.Children.Add(doubleAnimation); 500 501 var colorAnimation = new ColorAnimation 502 { 503 Duration = new Duration(new TimeSpan(0, 0, 0, 0, 200)), 504 To = Color.FromArgb(0, 0, 0, 0) 505 }; 506 507 Storyboard.SetTarget(colorAnimation, _shadowFragment); 508 Storyboard.SetTargetProperty(colorAnimation, ColorPath.Path); 509 shadow.Children.Add(colorAnimation); 510 511 shadow.Completed += shadow_Completed; 512 shadow.Begin(); 513 _shadowFragment.IsHitTestVisible = false; 514 } 515 #endregion 516 //#region ShowStatus 517 //public void ShowStatus(string info) 518 //{ 519 // rootPage.NotifyUser(info); 520 //} 521 //#endregion 522 523 } 524 }