Refactoring EntryCell SwitchCell renderer with Reusable feature
authorSeungkeun Lee <sngn.lee@samsung.com>
Mon, 19 Dec 2016 06:08:48 +0000 (15:08 +0900)
committerKangho Hur <kangho.hur@samsung.com>
Fri, 24 Mar 2017 04:18:57 +0000 (13:18 +0900)
 - Use Xamarin.Forms element to make Cell contents
 - Replace OnCellPropertyChanged code with binding feature
 - Implement Reusable cell feature

 - It need updated ElmSharp, beta-002 on nuget.org will be not working
 - Reusable feature of ElmSharp was submited with submit/tizen/20161214.052838 tag

Change-Id: I6d26259cae0da59c1476f5c5698d803ee3c5519f

Xamarin.Forms.Platform.Tizen/Cells/CellRenderer.cs
Xamarin.Forms.Platform.Tizen/Cells/EntryCellRenderer.cs
Xamarin.Forms.Platform.Tizen/Cells/SwitchCellRenderer.cs

index 4701905..449b6f3 100644 (file)
@@ -16,6 +16,7 @@ namespace Xamarin.Forms.Platform.Tizen
                                GetTextHandler = GetText,
                                GetContentHandler = GetContent,
                                DeleteHandler = ItemDeleted,
+                               ReusableContentHandler = ReusableContent,
                        };
                }
 
@@ -50,6 +51,11 @@ namespace Xamarin.Forms.Platform.Tizen
                {
                }
 
+               protected virtual EvasObject OnReusableContent(Cell cell, string part, EvasObject old)
+               {
+                       return null;
+               }
+
                protected int FindCellContentHeight(Cell cell)
                {
                        ViewCell viewCell = cell as ViewCell;
@@ -97,7 +103,9 @@ namespace Xamarin.Forms.Platform.Tizen
 
                internal void SendUnrealizedCell(Cell cell)
                {
-                       _realizedNativeViews.Remove(cell);
+                       Dictionary<string, EvasObject> realizedView = null;
+                       _realizedNativeViews.TryGetValue(cell, out realizedView);
+                       realizedView?.Clear();
                        OnUnrealizedCell(cell);
                }
 
@@ -111,6 +119,20 @@ namespace Xamarin.Forms.Platform.Tizen
                {
                        var cell = (data as Native.ListView.ItemContext).Cell;
                        EvasObject nativeView = OnGetContent(cell, part);
+                       UpdateRealizedView(cell, part, nativeView);
+                       return nativeView;
+               }
+
+               EvasObject ReusableContent(object data, string part, EvasObject old)
+               {
+                       var cell = (data as Native.ListView.ItemContext).Cell;
+                       EvasObject nativeView = OnReusableContent(cell, part, old);
+                       UpdateRealizedView(cell, part, nativeView);
+                       return nativeView;
+               }
+
+               void UpdateRealizedView(Cell cell, string part, EvasObject nativeView)
+               {
                        if (part != null && nativeView != null)
                        {
                                Dictionary<string, EvasObject> realizedView = null;
@@ -121,13 +143,7 @@ namespace Xamarin.Forms.Platform.Tizen
                                        _realizedNativeViews[cell] = realizedView;
                                }
                                realizedView[part] = nativeView;
-
-                               nativeView.Deleted += (sender, e) =>
-                               {
-                                       realizedView.Remove(part);
-                               };
                        }
-                       return nativeView;
                }
 
                void ItemDeleted(object data)
index 4c4e7f1..b74a6f9 100644 (file)
@@ -1,15 +1,17 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
 using ElmSharp;
 using EColor = ElmSharp.Color;
-using EBox = ElmSharp.Box;
-using System.Collections.Generic;
 
 namespace Xamarin.Forms.Platform.Tizen
 {
        public class EntryCellRenderer : ViewCellRenderer
        {
-               const int _defaultHeight = 120;
+               static readonly int s_defaultHeight = 120;
                static readonly EColor s_defaultLabelColor = EColor.Black;
-               readonly Dictionary<EvasObject, NativeEntryComponent> _realizedComponent = new Dictionary<EvasObject, NativeEntryComponent>();
+
+               readonly Dictionary<EvasObject, VisualElement> _cacheCandidate = new Dictionary<EvasObject, VisualElement>();
 
                public EntryCellRenderer()
                {
@@ -21,142 +23,79 @@ namespace Xamarin.Forms.Platform.Tizen
                        {
                                var entryCell = cell as EntryCell;
                                int height = (int)entryCell.RenderHeight;
-                               height = height <= 0 ? FindCellContentHeight(entryCell) : height;
-                               height = height <= 0 ? _defaultHeight : height;
+                               height = height > 0 ? height : s_defaultHeight;
 
-                               // TODO
-                               // Need to use Forms.Core element instead of using Elmsharp.
-                               // if we use Forms element, easily binding data to view elements
-                               var box = new EBox(Forms.Context.MainWindow)
+                               var label = new Label()
                                {
-                                       IsHorizontal = true,
-                                       MinimumHeight = height,
+                                       HorizontalOptions = LayoutOptions.Start,
+                                       VerticalOptions = LayoutOptions.Center,
+                                       VerticalTextAlignment = TextAlignment.Center,
+                                       FontSize = -1
                                };
-                               box.SetAlignment(-1.0, -1.0);  // fill
-                               box.SetWeight(1.0, 1.0);  // expand
+                               label.SetBinding(Label.TextProperty, new Binding(EntryCell.LabelProperty.PropertyName));
+                               label.SetBinding(Label.TextColorProperty, new Binding(EntryCell.LabelColorProperty.PropertyName, converter: new DefaultColorConverter()));
 
-                               var label = new Native.Label(box)
+                               var entry = new Entry()
                                {
-                                       Text = entryCell.Label,
-                                       TextColor = GetLabelColor(entryCell),
+                                       HorizontalOptions = LayoutOptions.FillAndExpand,
+                                       VerticalOptions = LayoutOptions.Center,
+                                       FontSize = -1,
                                };
-                               label.SetAlignment(0.0, 0.5);
-                               label.SetWeight(0.0, 1.0);
+                               entry.SetBinding(Entry.TextProperty, new Binding(EntryCell.TextProperty.PropertyName, BindingMode.TwoWay));
+                               entry.SetBinding(Entry.PlaceholderProperty, new Binding(EntryCell.PlaceholderProperty.PropertyName));
+                               entry.SetBinding(InputView.KeyboardProperty, new Binding(EntryCell.KeyboardProperty.PropertyName));
+                               entry.SetBinding(Entry.HorizontalTextAlignmentProperty, new Binding(EntryCell.HorizontalTextAlignmentProperty.PropertyName));
 
-                               var entry = new Native.Entry(box)
+                               var layout = new StackLayout()
                                {
-                                       IsSingleLine = true,
-                                       Text = entryCell.Text,
-                                       Placeholder = entryCell.Placeholder,
-                                       Keyboard = entryCell.Keyboard.ToNative(),
-                                       HorizontalTextAlignment = entryCell.HorizontalTextAlignment.ToNative(),
+                                       Orientation = StackOrientation.Horizontal,
+                                       Children = {
+                                               label,
+                                               entry
+                                       }
                                };
-                               entry.SetAlignment(-1.0, 0.5);
-                               entry.SetWeight(1.0, 1.0);
-
-                               box.PackEnd(label);
-                               box.PackEnd(entry);
-
-                               label.Show();
-                               entry.Show();
+                               layout.Parent = cell.Parent;
+                               layout.BindingContext = entryCell;
+                               layout.MinimumHeightRequest = height;
 
-                               entry.TextChanged += (sender, e) =>
-                               {
-                                       entryCell.Text = e.NewTextValue;
-                               };
-                               entry.Activated += (sender, e) =>
-                               {
-                                       (cell as IEntryCellController).SendCompleted();
-                               };
-                               NativeEntryComponent component = new NativeEntryComponent()
+                               var nativeView = Platform.GetOrCreateRenderer(layout).NativeView;
+                               nativeView.MinimumHeight = height;
+                               _cacheCandidate[nativeView] = layout;
+                               nativeView.Deleted += (sender, e) =>
                                {
-                                       Entry = entry,
-                                       Label = label,
+                                       _cacheCandidate.Remove(sender as EvasObject);
                                };
-                               _realizedComponent[box] = component;
-                               box.Deleted += (sender, e) =>
-                               {
-                                       _realizedComponent.Remove(box);
-                               };
-                               return box;
+                               return nativeView;
                        }
                        return null;
                }
 
-               protected override bool OnCellPropertyChanged(Cell cell, string property, Dictionary<string, EvasObject> realizedView)
+               protected override EvasObject OnReusableContent(Cell cell, string part, EvasObject old)
                {
-                       if (!realizedView.ContainsKey(MainContentPart) || !_realizedComponent.ContainsKey(realizedView[MainContentPart]))
+                       if (!_cacheCandidate.ContainsKey(old))
                        {
-                               return base.OnCellPropertyChanged(cell, property, realizedView);
+                               return null;
                        }
 
-                       NativeEntryComponent realizedCompoenet = _realizedComponent[realizedView[MainContentPart]];
-                       EntryCell entryCell = (EntryCell)cell;
+                       var layout = _cacheCandidate[old];
+                       layout.BindingContext = cell;
+                       int height = (int)cell.RenderHeight;
+                       height = height > 0 ? height : s_defaultHeight;
+                       old.MinimumHeight = height;
+                       return old;
+               }
 
-                       if (property == EntryCell.HorizontalTextAlignmentProperty.PropertyName)
-                       {
-                               var entry = realizedCompoenet.Entry;
-                               if (entry != null)
-                               {
-                                       entry.HorizontalTextAlignment = entryCell.HorizontalTextAlignment.ToNative();
-                               }
-                       }
-                       else if (property == EntryCell.KeyboardProperty.PropertyName)
-                       {
-                               var entry = realizedCompoenet.Entry;
-                               if (entry != null)
-                               {
-                                       entry.Keyboard = entryCell.Keyboard.ToNative();
-                               }
-                       }
-                       else if (property == EntryCell.PlaceholderProperty.PropertyName)
-                       {
-                               var entry = realizedCompoenet.Entry;
-                               if (entry != null)
-                               {
-                                       entry.Placeholder = entryCell.Placeholder;
-                               }
-                       }
-                       else if (property == EntryCell.TextProperty.PropertyName)
-                       {
-                               var entry = realizedCompoenet.Entry;
-                               if (entry != null)
-                               {
-                                       entry.Text = entryCell.Text;
-                               }
-                       }
-                       else if (property == EntryCell.LabelProperty.PropertyName)
-                       {
-                               var label = realizedCompoenet.Label;
-                               if (label != null)
-                               {
-                                       label.Text = entryCell.Label;
-                               }
-                       }
-                       else if (property == EntryCell.LabelColorProperty.PropertyName)
+               class DefaultColorConverter : IValueConverter
+               {
+                       public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
                        {
-                               var label = realizedCompoenet.Label;
-                               if (label != null)
-                               {
-                                       label.TextColor = GetLabelColor(entryCell);
-                               }
+                               return ((Color)value).IsDefault ? s_defaultLabelColor : value;
                        }
-                       else
+
+                       public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
                        {
-                               return base.OnCellPropertyChanged(cell, property, realizedView);
+                               return value;
                        }
-                       return false;
-               }
-
-               EColor GetLabelColor(EntryCell cell)
-               {
-                       return cell.LabelColor.IsDefault ? s_defaultLabelColor : cell.LabelColor.ToNative();
-               }
-
-               class NativeEntryComponent
-               {
-                       public Native.Entry Entry { get; set; }
-                       public Native.Label Label { get; set; }
                }
        }
 }
index 6c5a038..a676478 100644 (file)
@@ -5,9 +5,12 @@ namespace Xamarin.Forms.Platform.Tizen
 {
        public class SwitchCellRenderer : CellRenderer
        {
+               readonly Dictionary<EvasObject, VisualElement> _cacheCandidate = new Dictionary<EvasObject, VisualElement>();
+
                protected SwitchCellRenderer(string style) : base(style)
                {
                }
+
                public SwitchCellRenderer() : this("end_icon")
                {
                        MainPart = "elm.text";
@@ -33,41 +36,34 @@ namespace Xamarin.Forms.Platform.Tizen
                {
                        if (part == SwitchPart)
                        {
-                               var switchCell = cell as SwitchCell;
-                               var checkbox = new Check(Forms.Context.MainWindow)
+                               var toggle = new Switch()
                                {
-                                       Style = "on&off",
-                                       IsChecked = switchCell.On,
                                };
-
-                               checkbox.StateChanged += (sender, e) =>
-                               {
-                                       switchCell.On = e.NewState;
-                               };
-
-                               checkbox.SetAlignment(-1.0, -1.0);  // fill
-                               checkbox.SetWeight(1.0, 1.0);  // expand
-                               return checkbox;
+                               toggle.SetBinding(Switch.IsToggledProperty, new Binding(SwitchCell.OnProperty.PropertyName));
+                               toggle.BindingContext = cell;
+                               toggle.Parent = cell.Parent;
+                               var nativeView = Platform.GetOrCreateRenderer(toggle).NativeView;
+                               return nativeView;
                        }
                        return null;
                }
 
-               protected override bool OnCellPropertyChanged(Cell cell, string property, Dictionary<string, EvasObject> realizedView)
+               protected override EvasObject OnReusableContent(Cell cell, string part, EvasObject old)
                {
-                       if (property == SwitchCell.OnProperty.PropertyName && realizedView.ContainsKey(SwitchPart))
+                       if (!_cacheCandidate.ContainsKey(old))
                        {
-                               var checkbox = realizedView[SwitchPart] as Check;
-                               if (checkbox != null)
-                               {
-                                       checkbox.IsChecked = (cell as SwitchCell).On;
-                               }
-                               return false;
+                               return null;
                        }
-                       else if (property == SwitchCell.TextProperty.PropertyName)
+                       _cacheCandidate[old].BindingContext = cell;
+                       return old;
+               }
+
+               protected override bool OnCellPropertyChanged(Cell cell, string property, Dictionary<string, EvasObject> realizedView)
+               {
+                       if (property == SwitchCell.TextProperty.PropertyName)
                        {
                                return true;
                        }
-
                        return base.OnCellPropertyChanged(cell, property, realizedView);
                }
        }