2 * Copyright(c) 2019 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 using System.Collections.Generic;
19 using System.Runtime.InteropServices;
20 using System.ComponentModel;
21 using Tizen.NUI.Binding;
23 namespace Tizen.NUI.BaseComponents
27 /// ImageView is a class for displaying an image resource.<br />
28 /// An instance of ImageView can be created using a URL or an image instance.<br />
30 /// <since_tizen> 3 </since_tizen>
31 public partial class ImageView : View
33 static ImageView() { }
35 private EventHandler<ResourceReadyEventArgs> _resourceReadyEventHandler;
36 private ResourceReadyEventCallbackType _resourceReadyEventCallback;
37 private EventHandler<ResourceLoadedEventArgs> _resourceLoadedEventHandler;
38 private _resourceLoadedCallbackType _resourceLoadedCallback;
40 // Collection of image-sensitive properties.
41 private static readonly List<int> cachedImagePropertyKeyList = new List<int> {
43 ImageVisualProperty.URL,
44 ImageVisualProperty.AlphaMaskURL,
45 ImageVisualProperty.CropToMask,
46 Visual.Property.VisualFittingMode,
47 ImageVisualProperty.DesiredWidth,
48 ImageVisualProperty.DesiredHeight,
49 ImageVisualProperty.ReleasePolicy,
50 ImageVisualProperty.WrapModeU,
51 ImageVisualProperty.WrapModeV,
52 ImageVisualProperty.SynchronousLoading,
53 Visual.Property.PremultipliedAlpha,
54 ImageVisualProperty.OrientationCorrection,
55 NpatchImageVisualProperty.Border,
56 NpatchImageVisualProperty.BorderOnly,
58 internal PropertyMap cachedImagePropertyMap;
59 internal bool imagePropertyUpdatedFlag = false;
61 private bool imagePropertyUpdateProcessAttachedFlag = false;
62 private Rectangle _border;
63 private string _resourceUrl = "";
64 private int _desired_width = -1;
65 private int _desired_height = -1;
66 private TriggerableSelector<string> resourceUrlSelector;
67 private TriggerableSelector<Rectangle> borderSelector;
70 /// Creates an initialized ImageView.
72 /// <since_tizen> 3 </since_tizen>
73 public ImageView() : this(Interop.ImageView.New(), true)
75 if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
78 /// This will be public opened in next release of tizen after ACR done. Before ACR, it is used as HiddenAPI (InhouseAPI).
79 [EditorBrowsable(EditorBrowsableState.Never)]
80 public ImageView(ViewStyle viewStyle) : this(Interop.ImageView.New(), true, viewStyle)
85 /// Creates an initialized ImageView with setting the status of shown or hidden.
87 /// <param name="shown">false : Not displayed (hidden), true : displayed (shown)</param>
88 /// This will be public opened in next release of tizen after ACR done. Before ACR, it is used as HiddenAPI (InhouseAPI).
89 [EditorBrowsable(EditorBrowsableState.Never)]
90 public ImageView(bool shown) : this(Interop.ImageView.New(), true)
92 if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
97 /// Creates an initialized ImageView from a URL to an image resource.<br />
98 /// If the string is empty, ImageView will not display anything.<br />
100 /// <param name="url">The URL of the image resource to display.</param>
101 /// <since_tizen> 3 </since_tizen>
102 public ImageView(string url) : this(Interop.ImageView.New(url), true)
105 if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
110 /// Creates an initialized ImageView from a URL to an image resource with setting shown or hidden.
112 /// <param name="url">The URL of the image resource to display.</param>
113 /// <param name="shown">false : Not displayed (hidden), true : displayed (shown)</param>
114 /// This will be public opened in next release of tizen after ACR done. Before ACR, it is used as HiddenAPI (InhouseAPI).
115 [EditorBrowsable(EditorBrowsableState.Never)]
116 public ImageView(string url, bool shown) : this(Interop.ImageView.New(url), true)
119 if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
123 internal ImageView(string url, Uint16Pair size, bool shown = true) : this(Interop.ImageView.New(url, Uint16Pair.getCPtr(size)), true)
126 if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
134 internal ImageView(global::System.IntPtr cPtr, bool cMemoryOwn, ViewStyle viewStyle, bool shown = true) : base(cPtr, cMemoryOwn, viewStyle)
142 internal ImageView(global::System.IntPtr cPtr, bool cMemoryOwn, bool shown = true) : base(cPtr, cMemoryOwn, null)
150 [UnmanagedFunctionPointer(CallingConvention.StdCall)]
151 private delegate void ResourceReadyEventCallbackType(IntPtr data);
152 [UnmanagedFunctionPointer(CallingConvention.StdCall)]
153 private delegate void _resourceLoadedCallbackType(IntPtr view);
156 /// An event for ResourceReady signal which can be used to subscribe or unsubscribe the event handler.<br />
157 /// This signal is emitted after all resources required by a control are loaded and ready.<br />
158 /// Most resources are only loaded when the control is placed on the stage.<br />
160 /// <since_tizen> 3 </since_tizen>
161 public event EventHandler<ResourceReadyEventArgs> ResourceReady
165 if (_resourceReadyEventHandler == null)
167 _resourceReadyEventCallback = OnResourceReady;
168 ViewResourceReadySignal resourceReadySignal = ResourceReadySignal(this);
169 resourceReadySignal?.Connect(_resourceReadyEventCallback);
170 resourceReadySignal?.Dispose();
173 _resourceReadyEventHandler += value;
178 _resourceReadyEventHandler -= value;
180 ViewResourceReadySignal resourceReadySignal = ResourceReadySignal(this);
181 if (_resourceReadyEventHandler == null && resourceReadySignal?.Empty() == false)
183 resourceReadySignal?.Disconnect(_resourceReadyEventCallback);
185 resourceReadySignal?.Dispose();
189 internal event EventHandler<ResourceLoadedEventArgs> ResourceLoaded
193 if (_resourceLoadedEventHandler == null)
195 _resourceLoadedCallback = OnResourceLoaded;
196 ViewResourceReadySignal resourceReadySignal = this.ResourceReadySignal(this);
197 resourceReadySignal?.Connect(_resourceLoadedCallback);
198 resourceReadySignal?.Dispose();
201 _resourceLoadedEventHandler += value;
205 _resourceLoadedEventHandler -= value;
206 ViewResourceReadySignal resourceReadySignal = this.ResourceReadySignal(this);
207 if (_resourceLoadedEventHandler == null && resourceReadySignal?.Empty() == false)
209 resourceReadySignal?.Disconnect(_resourceLoadedCallback);
211 resourceReadySignal?.Dispose();
216 /// Enumeration for LoadingStatus of image.
218 /// <since_tizen> 5 </since_tizen>
219 public enum LoadingStatusType
222 /// Loading preparing status.
224 /// <since_tizen> 5 </since_tizen>
227 /// Loading ready status.
229 /// <since_tizen> 5 </since_tizen>
232 /// Loading failed status.
234 /// <since_tizen> 5 </since_tizen>
239 /// ImageView ResourceUrl, type string.
240 /// This is one of mandatory property. Even if not set or null set, it sets empty string ("") internally.
241 /// When it is set as null, it gives empty string ("") to be read.
243 /// <since_tizen> 3 </since_tizen>
244 public string ResourceUrl
248 return (string)GetValue(ResourceUrlProperty);
252 SetValue(ResourceUrlProperty, value);
253 NotifyPropertyChanged();
258 /// This will be deprecated, please use Image instead. <br />
259 /// ImageView ImageMap, type PropertyMap: string if it is a URL, map otherwise.
261 /// <since_tizen> 3 </since_tizen>
262 [Obsolete("Please do not use! This will be deprecated! Please use Image property instead!")]
263 [EditorBrowsable(EditorBrowsableState.Never)]
264 public PropertyMap ImageMap
268 return GetValue(ImageMapProperty) as PropertyMap;
272 SetValue(ImageMapProperty, value);
273 NotifyPropertyChanged();
276 private PropertyMap InternalImageMap
282 // Sync as current properties
285 // Get current properties force.
286 PropertyMap returnValue = new PropertyMap();
287 PropertyValue image = GetProperty(ImageView.Property.IMAGE);
288 image?.Get(returnValue);
291 // Update cached property map
292 if(returnValue != null)
294 MergeCachedImageVisualProperty(returnValue);
307 PropertyValue setValue = new Tizen.NUI.PropertyValue(value);
308 SetProperty(ImageView.Property.IMAGE, setValue);
310 // Image properties are changed hardly. We should ignore lazy UpdateImage
311 imagePropertyUpdatedFlag = false;
312 cachedImagePropertyMap?.Dispose();
313 cachedImagePropertyMap = null;
314 MergeCachedImageVisualProperty(value);
316 NotifyPropertyChanged();
323 /// ImageView Image, type PropertyMap: string if it is a URL, map otherwise.
326 /// This PropertyMap use a <see cref="ImageVisualProperty"/>. <br />
327 /// See <see cref="ImageVisualProperty"/> for a detailed description. <br />
328 /// you can also use <see cref="Visual.Property"/>. <br />
329 /// See <see cref="Visual.Property"/> for a detailed description. <br />
332 /// The following example demonstrates how to use the Image property.
334 /// PropertyMap map = new PropertyMap();
335 /// map.Insert(Visual.Property.Type, new PropertyValue((int)Visual.Type.Image));
336 /// map.Insert(ImageVisualProperty.AlphaMaskURL, new PropertyValue(url));
337 /// map.Insert(ImageVisualProperty.FittingMode, new PropertyValue((int)FittingModeType.ScaleToFill);
338 /// imageview.Image = map;
341 /// <since_tizen> 4 </since_tizen>
342 public PropertyMap Image
348 return (PropertyMap)GetValue(ImageProperty);
359 SetValue(ImageProperty, value);
360 NotifyPropertyChanged();
366 /// ImageView PreMultipliedAlpha, type Boolean.<br />
367 /// Image must be initialized.<br />
369 /// <since_tizen> 3 </since_tizen>
370 public bool PreMultipliedAlpha
374 return (bool)GetValue(PreMultipliedAlphaProperty);
378 SetValue(PreMultipliedAlphaProperty, value);
379 NotifyPropertyChanged();
384 /// ImageView PixelArea, type Vector4 (Animatable property).<br />
385 /// Pixel area is a relative value with the whole image area as [0.0, 0.0, 1.0, 1.0].<br />
388 /// The property cascade chaining set is possible. For example, this (imageView.PixelArea.X = 0.1f;) is possible.
390 /// <since_tizen> 3 </since_tizen>
391 public RelativeVector4 PixelArea
395 RelativeVector4 temp = (RelativeVector4)GetValue(PixelAreaProperty);
396 return new RelativeVector4(OnPixelAreaChanged, temp.X, temp.Y, temp.Z, temp.W);
400 SetValue(PixelAreaProperty, value);
401 NotifyPropertyChanged();
406 /// The border of the image in the order: left, right, bottom, top.<br />
407 /// If set, ImageMap will be ignored.<br />
408 /// For N-Patch images only.<br />
412 /// The property cascade chaining set is possible. For example, this (imageView.Border.X = 1;) is possible.
414 /// <since_tizen> 3 </since_tizen>
415 public Rectangle Border
419 Rectangle temp = (Rectangle)GetValue(BorderProperty);
426 return new Rectangle(OnBorderChanged, temp.X, temp.Y, temp.Width, temp.Height);
431 SetValue(BorderProperty, value);
432 NotifyPropertyChanged();
437 /// Gets or sets whether to draw the borders only (if true).<br />
438 /// If not specified, the default is false.<br />
439 /// For N-Patch images only.<br />
442 /// <since_tizen> 3 </since_tizen>
443 public bool BorderOnly
447 return (bool)GetValue(BorderOnlyProperty);
451 SetValue(BorderOnlyProperty, value);
452 NotifyPropertyChanged();
457 /// Gets or sets whether to synchronous loading the resourceurl of image.<br />
459 /// <since_tizen> 3 </since_tizen>
460 [Obsolete("Deprecated since API level 9 and will be removed in API level 11. Please use SynchronousLoading instead!")]
461 public bool SynchronosLoading
465 return SynchronousLoading;
469 SynchronousLoading = value;
474 /// Gets or sets whether the image of the ResourceUrl property will be loaded synchronously.<br />
477 /// Changing this property make this ImageView load image synchronously at the next loading
478 /// by following operation: <see cref="Reload"/>, <see cref="SetImage(string)"/>,
479 /// and by some properties those cause reloading: <see cref="ResourceUrl"/>, <see cref="PreMultipliedAlpha"/> and etc.
481 /// <since_tizen> 9 </since_tizen>
482 public bool SynchronousLoading
486 return (bool)GetValue(SynchronousLoadingProperty);
490 SetValue(SynchronousLoadingProperty, value);
491 NotifyPropertyChanged();
496 /// Gets or sets whether to automatically correct the orientation of an image.<br />
498 /// <since_tizen> 5 </since_tizen>
499 public bool OrientationCorrection
503 return (bool)GetValue(OrientationCorrectionProperty);
507 SetValue(OrientationCorrectionProperty, value);
508 NotifyPropertyChanged();
513 /// Gets the loading state of the visual resource.
515 /// <since_tizen> 5 </since_tizen>
516 public ImageView.LoadingStatusType LoadingStatus
520 return (ImageView.LoadingStatusType)Interop.View.GetVisualResourceStatus(SwigCPtr, (int)Property.IMAGE);
525 /// Downcasts a handle to imageView handle.
527 /// <exception cref="ArgumentNullException"> Thrown when handle is null. </exception>
528 /// Please do not use! this will be deprecated!
529 /// Instead please use as keyword.
530 /// <since_tizen> 3 </since_tizen>
531 [Obsolete("Please do not use! This will be deprecated! Please use as keyword instead! " +
533 "BaseHandle handle = new ImageView(imagePath); " +
534 "ImageView image = handle as ImageView")]
535 [EditorBrowsable(EditorBrowsableState.Never)]
536 public static ImageView DownCast(BaseHandle handle)
540 throw new ArgumentNullException(nameof(handle));
542 ImageView ret = Registry.GetManagedBaseHandleFromNativePtr(handle) as ImageView;
543 if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
548 /// Sets this ImageView from the given URL.<br />
549 /// If the URL is empty, ImageView will not display anything.<br />
551 /// <param name="url">The URL to the image resource to display.</param>
552 /// <exception cref="ArgumentNullException"> Thrown when url is null. </exception>
553 /// <since_tizen> 3 </since_tizen>
554 public void SetImage(string url)
558 throw new ArgumentNullException(nameof(url));
561 if (url.Contains(".json"))
563 Tizen.Log.Fatal("NUI", "[ERROR] Please DO NOT set lottie file in ImageView! This is temporary checking, will be removed soon!");
567 Interop.ImageView.SetImage(SwigCPtr, url);
568 if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
574 /// Queries if all resources required by a control are loaded and ready.<br />
575 /// Most resources are only loaded when the control is placed on the stage.<br />
576 /// True if the resources are loaded and ready, false otherwise.<br />
578 /// <since_tizen> 3 </since_tizen>
579 public new bool IsResourceReady()
581 bool ret = Interop.View.IsResourceReady(SwigCPtr);
582 if (NDalicPINVOKE.SWIGPendingException.Pending)
583 throw NDalicPINVOKE.SWIGPendingException.Retrieve();
588 /// Forcefully reloads the image. All the visuals using this image will reload to the latest image.
590 /// <since_tizen> 5 </since_tizen>
593 // Sync as current properties
596 PropertyValue attributes = new PropertyValue(0);
597 this.DoAction(ImageView.Property.IMAGE, ActionReload, attributes);
598 attributes?.Dispose();
602 /// Plays the animated GIF. This is also the default playback mode.
604 /// <since_tizen> 5 </since_tizen>
607 // Sync as current properties
610 PropertyValue attributes = new PropertyValue(0);
611 this.DoAction(ImageView.Property.IMAGE, ActionPlay, attributes);
612 attributes?.Dispose();
616 /// Pauses the animated GIF.
618 /// <since_tizen> 5 </since_tizen>
621 // Sync as current properties
624 PropertyValue attributes = new PropertyValue(0);
625 this.DoAction(ImageView.Property.IMAGE, ActionPause, attributes);
626 attributes?.Dispose();
630 /// Stops the animated GIF.
632 /// <since_tizen> 5 </since_tizen>
635 // Sync as current properties
638 PropertyValue attributes = new PropertyValue(0);
639 this.DoAction(ImageView.Property.IMAGE, ActionStop, attributes);
640 attributes?.Dispose();
644 /// Gets or sets the URL of the alpha mask.<br />
647 /// <since_tizen> 6</since_tizen>
648 [EditorBrowsable(EditorBrowsableState.Never)]
649 public string AlphaMaskURL
653 return GetValue(AlphaMaskURLProperty) as string;
657 SetValue(AlphaMaskURLProperty, value);
658 NotifyPropertyChanged();
662 private string InternalAlphaMaskURL
668 PropertyValue maskUrl = GetCachedImageVisualProperty(ImageVisualProperty.AlphaMaskURL);
669 maskUrl?.Get(out ret);
676 PropertyValue setValue = new PropertyValue(value ?? "");
677 UpdateImage(ImageVisualProperty.AlphaMaskURL, setValue);
678 // When we never set CropToMask property before, we should set default value as true.
679 using(PropertyValue cropToMask = GetCachedImageVisualProperty(ImageVisualProperty.CropToMask))
681 if(cropToMask == null)
683 using PropertyValue setCropValue = new PropertyValue(true);
684 UpdateImage(ImageVisualProperty.CropToMask, setCropValue);
693 /// Whether to crop image to mask or scale mask to fit image.
695 /// <since_tizen> 6 </since_tizen>
696 public bool CropToMask
700 return (bool)GetValue(CropToMaskProperty);
704 SetValue(CropToMaskProperty, value);
705 NotifyPropertyChanged();
708 private bool InternalCropToMask
714 PropertyValue cropToMask = GetCachedImageVisualProperty(ImageVisualProperty.CropToMask);
715 cropToMask?.Get(out ret);
716 cropToMask?.Dispose();
722 PropertyValue setValue = new PropertyValue(value);
723 UpdateImage(ImageVisualProperty.CropToMask, setValue);
729 /// Actions property value for Reload image.
731 private int ActionReload { get; set; } = Interop.ImageView.ImageVisualActionReloadGet();
734 /// Actions property value to Play animated images.
735 /// This property can be redefined by child class if it use different value.
737 [EditorBrowsable(EditorBrowsableState.Never)]
738 protected int ActionPlay { get; set; } = Interop.AnimatedImageView.AnimatedImageVisualActionPlayGet();
741 /// Actions property value to Pause animated images.
742 /// This property can be redefined by child class if it use different value.
744 [EditorBrowsable(EditorBrowsableState.Never)]
745 protected int ActionPause { get; set; } = Interop.AnimatedImageView.AnimatedImageVisualActionPauseGet();
748 /// Actions property value to Stop animated images.
749 /// This property can be redefined by child class if it use different value.
751 [EditorBrowsable(EditorBrowsableState.Never)]
752 protected int ActionStop { get; set; } = Interop.AnimatedImageView.AnimatedImageVisualActionStopGet();
754 internal VisualFittingModeType ConvertFittingModetoVisualFittingMode(FittingModeType value)
758 case FittingModeType.ShrinkToFit:
759 return VisualFittingModeType.FitKeepAspectRatio;
760 case FittingModeType.ScaleToFill:
761 return VisualFittingModeType.OverFitKeepAspectRatio;
762 case FittingModeType.Center:
763 return VisualFittingModeType.Center;
764 case FittingModeType.Fill:
765 return VisualFittingModeType.Fill;
766 case FittingModeType.FitHeight:
767 return VisualFittingModeType.FitHeight;
768 case FittingModeType.FitWidth:
769 return VisualFittingModeType.FitWidth;
771 return VisualFittingModeType.Fill;
775 internal FittingModeType ConvertVisualFittingModetoFittingMode(VisualFittingModeType value)
779 case VisualFittingModeType.FitKeepAspectRatio:
780 return FittingModeType.ShrinkToFit;
781 case VisualFittingModeType.OverFitKeepAspectRatio:
782 return FittingModeType.ScaleToFill;
783 case VisualFittingModeType.Center:
784 return FittingModeType.Center;
785 case VisualFittingModeType.Fill:
786 return FittingModeType.Fill;
787 case VisualFittingModeType.FitHeight:
788 return FittingModeType.FitHeight;
789 case VisualFittingModeType.FitWidth:
790 return FittingModeType.FitWidth;
792 return FittingModeType.ShrinkToFit;
796 internal override LayoutItem CreateDefaultLayout()
798 return new ImageLayout();
802 /// Gets or sets fitting options used when resizing images to fit.<br />
803 /// If not supplied, the default is FittingModeType.Fill.<br />
804 /// For normal quad images only.<br />
807 /// <since_tizen> 6 </since_tizen>
808 [EditorBrowsable(EditorBrowsableState.Never)]
809 public FittingModeType FittingMode
813 return (FittingModeType)GetValue(FittingModeProperty);
817 SetValue(FittingModeProperty, value);
818 NotifyPropertyChanged();
822 private FittingModeType InternalFittingMode
826 int ret = (int)VisualFittingModeType.Fill;
828 PropertyValue fittingMode = GetCachedImageVisualProperty(Visual.Property.VisualFittingMode);
829 fittingMode?.Get(out ret);
830 fittingMode?.Dispose();
832 return ConvertVisualFittingModetoFittingMode((VisualFittingModeType)ret);
836 VisualFittingModeType ret = ConvertFittingModetoVisualFittingMode(value);
837 PropertyValue setValue = new PropertyValue((int)ret);
838 UpdateImage(Visual.Property.VisualFittingMode, setValue);
846 /// Gets or sets the desired image width.<br />
847 /// If not specified, the actual image width is used.<br />
848 /// For normal quad images only.<br />
851 /// <since_tizen> 6 </since_tizen>
852 [EditorBrowsable(EditorBrowsableState.Never)]
853 public int DesiredWidth
857 return (int)GetValue(DesiredWidthProperty);
861 SetValue(DesiredWidthProperty, value);
862 NotifyPropertyChanged();
865 private int InternalDesiredWidth
869 // Sync as current properties only if both _desired_width and _desired_height are setuped.
870 if(_desired_width != -1 && _desired_height != -1)
874 PropertyValue desirewidth = GetCachedImageVisualProperty(ImageVisualProperty.DesiredWidth);
875 desirewidth?.Get(out _desired_width);
876 desirewidth?.Dispose();
878 return _desired_width;
882 if (_desired_width != value)
884 _desired_width = value;
885 PropertyValue setValue = new PropertyValue(value);
886 UpdateImage(ImageVisualProperty.DesiredWidth, setValue);
893 /// Gets or sets the desired image height.<br />
894 /// If not specified, the actual image height is used.<br />
895 /// For normal quad images only.<br />
898 /// <since_tizen> 6 </since_tizen>
899 [EditorBrowsable(EditorBrowsableState.Never)]
900 public int DesiredHeight
904 return (int)GetValue(DesiredHeightProperty);
908 SetValue(DesiredHeightProperty, value);
909 NotifyPropertyChanged();
912 private int InternalDesiredHeight
916 // Sync as current properties only if both _desired_width and _desired_height are setuped.
917 if(_desired_width != -1 && _desired_height != -1)
921 PropertyValue desireheight = GetCachedImageVisualProperty(ImageVisualProperty.DesiredHeight);
922 desireheight?.Get(out _desired_height);
923 desireheight?.Dispose();
925 return _desired_height;
929 if (_desired_height != value)
931 _desired_height = value;
932 PropertyValue setValue = new PropertyValue(value);
933 UpdateImage(ImageVisualProperty.DesiredHeight, setValue);
940 /// Gets or sets ReleasePolicy for image.<br />
941 /// If not supplied, the default is ReleasePolicyType.Detached.<br />
943 [EditorBrowsable(EditorBrowsableState.Never)]
944 public ReleasePolicyType ReleasePolicy
948 return (ReleasePolicyType)GetValue(ReleasePolicyProperty);
952 SetValue(ReleasePolicyProperty, value);
953 NotifyPropertyChanged();
957 private ReleasePolicyType InternalReleasePolicy
961 int ret = (int)ReleasePolicyType.Detached;
963 PropertyValue releasePoli = GetCachedImageVisualProperty(ImageVisualProperty.ReleasePolicy);
964 releasePoli?.Get(out ret);
965 releasePoli?.Dispose();
967 return (ReleasePolicyType)ret;
971 PropertyValue setValue = new PropertyValue((int)value);
972 UpdateImage(ImageVisualProperty.ReleasePolicy, setValue);
978 /// Gets or sets the wrap mode for the u coordinate.<br />
979 /// It decides how the texture should be sampled when the u coordinate exceeds the range of 0.0 to 1.0.<br />
980 /// If not specified, the default is WrapModeType.Default(CLAMP).<br />
981 /// For normal quad images only.<br />
984 /// <since_tizen> 6 </since_tizen>
985 [EditorBrowsable(EditorBrowsableState.Never)]
986 public WrapModeType WrapModeU
990 return (WrapModeType)GetValue(WrapModeUProperty);
994 SetValue(WrapModeUProperty, value);
995 NotifyPropertyChanged();
999 private WrapModeType InternalWrapModeU
1003 int ret = (int)WrapModeType.Default;
1005 PropertyValue wrapModeU = GetCachedImageVisualProperty(ImageVisualProperty.WrapModeU);
1006 wrapModeU?.Get(out ret);
1007 wrapModeU?.Dispose();
1009 return (WrapModeType)ret;
1013 PropertyValue setValue = new PropertyValue((int)value);
1014 UpdateImage(ImageVisualProperty.WrapModeU, setValue);
1015 setValue?.Dispose();
1020 /// Gets or sets the wrap mode for the v coordinate.<br />
1021 /// It decides how the texture should be sampled when the v coordinate exceeds the range of 0.0 to 1.0.<br />
1022 /// The first two elements indicate the top-left position of the area, and the last two elements are the areas of the width and the height respectively.<br />
1023 /// If not specified, the default is WrapModeType.Default(CLAMP).<br />
1024 /// For normal quad images only.
1027 /// <since_tizen> 6 </since_tizen>
1028 [EditorBrowsable(EditorBrowsableState.Never)]
1029 public WrapModeType WrapModeV
1033 return (WrapModeType)GetValue(WrapModeVProperty);
1037 SetValue(WrapModeVProperty, value);
1038 NotifyPropertyChanged();
1042 private WrapModeType InternalWrapModeV
1046 int ret = (int)WrapModeType.Default;
1048 PropertyValue wrapModeV = GetCachedImageVisualProperty(ImageVisualProperty.WrapModeV);
1049 wrapModeV?.Get(out ret);
1050 wrapModeV?.Dispose();
1052 return (WrapModeType)ret;
1056 PropertyValue setValue = new PropertyValue((int)value);
1057 UpdateImage(ImageVisualProperty.WrapModeV, setValue);
1058 setValue?.Dispose();
1063 /// Gets or sets the mode to adjust view size to preserve the aspect ratio of the image resource.
1066 /// This is false by default.
1067 /// If this is set to be true, then the width or height value, which is not set by user explicitly, can be changed automatically
1068 /// to preserve the aspect ratio of the image resource.
1069 /// AdjustViewSize works only if ImageView is added to a View having Layout.
1070 /// e.g. If the image resource size is (100, 100), then the ImageView requests size (100, 100) to its parent layout by default.
1071 /// If the ImageView's HeightSpecification is 50 and AdjustViewSize is true, then the ImageView requests size (50, 50) instead of (100, 50).
1073 /// <since_tizen> 9 </since_tizen>
1074 public bool AdjustViewSize
1078 return (bool)GetValue(AdjustViewSizeProperty);
1082 SetValue(AdjustViewSizeProperty, value);
1083 NotifyPropertyChanged();
1086 private bool adjustViewSize = false;
1088 internal Selector<string> ResourceUrlSelector
1090 get => GetSelector<string>(resourceUrlSelector, ImageView.ResourceUrlProperty);
1093 resourceUrlSelector?.Reset(this);
1094 if (value == null) return;
1096 if (value.HasAll()) SetResourceUrl(value.All);
1097 else resourceUrlSelector = new TriggerableSelector<string>(this, value, SetResourceUrl, true);
1102 /// Get attributes, it is abstract function and must be override.
1104 [EditorBrowsable(EditorBrowsableState.Never)]
1105 protected override ViewStyle CreateViewStyle()
1107 return new ImageViewStyle();
1110 internal void SetImage(string url, Uint16Pair size)
1112 if (url.Contains(".json"))
1114 Tizen.Log.Fatal("NUI", "[ERROR] Please DO NOT set lottie file in ImageView! This is temporary checking, will be removed soon!");
1118 Interop.ImageView.SetImage(SwigCPtr, url, Uint16Pair.getCPtr(size));
1119 if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
1124 internal ViewResourceReadySignal ResourceReadySignal(View view)
1126 ViewResourceReadySignal ret = new ViewResourceReadySignal(Interop.View.ResourceReadySignal(View.getCPtr(view)), false);
1127 if (NDalicPINVOKE.SWIGPendingException.Pending) throw NDalicPINVOKE.SWIGPendingException.Retrieve();
1131 internal override void ApplyCornerRadius()
1133 base.ApplyCornerRadius();
1135 if (backgroundExtraData == null) return;
1137 // Apply corner radius to IMAGE.
1138 var cornerRadiusValue = backgroundExtraData.CornerRadius == null ? new PropertyValue() : new PropertyValue(backgroundExtraData.CornerRadius);
1139 var cornerRadiusPolicyValue = new PropertyValue((int)backgroundExtraData.CornerRadiusPolicy);
1141 // Make current propertyMap
1142 PropertyMap currentPropertyMap = new PropertyMap();
1143 currentPropertyMap[Visual.Property.CornerRadius] = cornerRadiusValue;
1144 currentPropertyMap[Visual.Property.CornerRadiusPolicy] = cornerRadiusPolicyValue;
1145 var temp = new PropertyValue(currentPropertyMap);
1147 // Update corner radius properties to image by ActionUpdateProperty
1148 this.DoAction(ImageView.Property.IMAGE, ActionUpdateProperty, temp);
1151 currentPropertyMap.Dispose();
1152 cornerRadiusValue.Dispose();
1153 cornerRadiusPolicyValue.Dispose();
1156 internal override void ApplyBorderline()
1158 base.ApplyBorderline();
1160 if (backgroundExtraData == null) return;
1162 // Apply borderline to IMAGE.
1163 var borderlineWidthValue = new PropertyValue(backgroundExtraData.BorderlineWidth);
1164 var borderlineColorValue = backgroundExtraData.BorderlineColor == null ? new PropertyValue(Color.Black) : new PropertyValue(backgroundExtraData.BorderlineColor);
1165 var borderlineOffsetValue = new PropertyValue(backgroundExtraData.BorderlineOffset);
1167 // Make current propertyMap
1168 PropertyMap currentPropertyMap = new PropertyMap();
1169 currentPropertyMap[Visual.Property.BorderlineWidth] = borderlineWidthValue;
1170 currentPropertyMap[Visual.Property.BorderlineColor] = borderlineColorValue;
1171 currentPropertyMap[Visual.Property.BorderlineOffset] = borderlineOffsetValue;
1172 var temp = new PropertyValue(currentPropertyMap);
1174 // Update borderline properties to image by ActionUpdateProperty
1175 this.DoAction(ImageView.Property.IMAGE, ActionUpdateProperty, temp);
1178 currentPropertyMap.Dispose();
1179 borderlineWidthValue.Dispose();
1180 borderlineColorValue.Dispose();
1181 borderlineOffsetValue.Dispose();
1184 internal ResourceLoadingStatusType GetResourceStatus()
1186 return (ResourceLoadingStatusType)Interop.View.GetVisualResourceStatus(this.SwigCPtr, Property.IMAGE);
1190 /// you can override it to clean-up your own resources.
1192 /// <param name="type">DisposeTypes</param>
1193 /// <since_tizen> 3 </since_tizen>
1194 protected override void Dispose(DisposeTypes type)
1201 if (type == DisposeTypes.Explicit)
1204 //Release your own managed resources here.
1205 //You should release all of your own disposable objects here.
1208 borderSelector?.Reset(this);
1209 resourceUrlSelector?.Reset(this);
1210 imagePropertyUpdatedFlag = false;
1211 if (imagePropertyUpdateProcessAttachedFlag)
1213 ProcessorController.Instance.ProcessorOnceEvent -= UpdateImage;
1214 imagePropertyUpdateProcessAttachedFlag = false;
1216 cachedImagePropertyMap?.Dispose();
1217 cachedImagePropertyMap = null;
1223 /// This will not be public opened.
1224 [EditorBrowsable(EditorBrowsableState.Never)]
1225 protected override void ReleaseSwigCPtr(System.Runtime.InteropServices.HandleRef swigCPtr)
1227 Interop.ImageView.DeleteImageView(swigCPtr);
1230 // Callback for View ResourceReady signal
1231 private void OnResourceReady(IntPtr data)
1233 ResourceReadyEventArgs e = new ResourceReadyEventArgs();
1236 e.View = Registry.GetManagedBaseHandleFromNativePtr(data) as View;
1239 if (_resourceReadyEventHandler != null)
1241 _resourceReadyEventHandler(this, e);
1245 private void SetResourceUrl(string value)
1247 value = (value == null ? "" : value);
1248 if (value.StartsWith("*Resource*"))
1250 string resource = Tizen.Applications.Application.Current.DirectoryInfo.Resource;
1251 value = value.Replace("*Resource*", resource);
1253 if(_resourceUrl != value)
1255 _resourceUrl = value;
1256 if(string.IsNullOrEmpty(_resourceUrl))
1258 // Special case. If we set ResourceUrl as empty, Unregist visual.
1263 using(PropertyValue setValue = new PropertyValue(value))
1265 UpdateImage(ImageVisualProperty.URL, setValue);
1271 private void SetBorder(Rectangle value)
1277 if(_border != value)
1279 _border = new Rectangle(value);
1280 UpdateImage(NpatchImageVisualProperty.Border, new PropertyValue(_border));
1285 /// Unregist image visual directly. After this operation, we cannot get any properties from Image property.
1287 private void RemoveImage()
1289 // If previous resourceUrl was already empty, we don't need to do anything. just ignore.
1290 // Unregist and detach process only if previous resourceUrl was not empty
1291 string currentResourceUrl = "";
1292 PropertyValue currentResourceUrlValue = GetCachedImageVisualProperty(ImageVisualProperty.URL);
1293 if((currentResourceUrlValue?.Get(out currentResourceUrl) ?? false) && !string.IsNullOrEmpty(currentResourceUrl))
1295 PropertyValue emptyValue = new PropertyValue();
1297 // Remove current registed Image.
1298 SetProperty(ImageView.Property.IMAGE, emptyValue);
1300 // Image visual is not exist anymore. We should ignore lazy UpdateImage
1301 imagePropertyUpdatedFlag = false;
1302 if(imagePropertyUpdateProcessAttachedFlag)
1304 ProcessorController.Instance.ProcessorOnceEvent -= UpdateImage;
1305 imagePropertyUpdateProcessAttachedFlag = false;
1307 // Update resourceUrl as empty value
1308 cachedImagePropertyMap[ImageVisualProperty.URL] = emptyValue;
1310 emptyValue?.Dispose();
1312 currentResourceUrlValue?.Dispose();
1316 /// Lazy call to UpdateImage.
1317 /// Collect Properties need to be update, and set properties that starts the Processing.
1319 [EditorBrowsable(EditorBrowsableState.Never)]
1320 protected virtual void UpdateImage(int key, PropertyValue value)
1322 // Update image property map value as inputed value.
1325 if (cachedImagePropertyMap == null)
1327 cachedImagePropertyMap = new PropertyMap();
1329 imagePropertyUpdatedFlag = true;
1330 cachedImagePropertyMap[key] = value;
1332 // Lazy update only if _resourceUrl is not empty and ProcessAttachedFlag is false.
1333 if (!string.IsNullOrEmpty(_resourceUrl) && !imagePropertyUpdateProcessAttachedFlag)
1335 imagePropertyUpdateProcessAttachedFlag = true;
1336 ProcessorController.Instance.ProcessorOnceEvent += UpdateImage;
1337 // Call process hardly.
1338 ProcessorController.Instance.Awake();
1344 /// Callback function to Lazy UpdateImage.
1346 private void UpdateImage(object source, EventArgs e)
1349 imagePropertyUpdateProcessAttachedFlag = false;
1353 /// Update image-relative properties synchronously.
1354 /// After call this API, All image properties updated.
1357 /// Current version ImageView property update asynchronously.
1358 /// If you want to guarantee that ImageView property setuped,
1359 /// Please call this ImageView.UpdateImage() API.
1361 [EditorBrowsable(EditorBrowsableState.Never)]
1362 protected virtual void UpdateImage()
1364 if(!imagePropertyUpdatedFlag) return;
1366 imagePropertyUpdatedFlag = false;
1368 if(cachedImagePropertyMap == null)
1370 cachedImagePropertyMap = new PropertyMap();
1373 // Checkup the cached visual type is AnimatedImage.
1374 // It is trick to know that this code is running on AnimatedImageView.UpdateImage() or not.
1375 int visualType = -1;
1376 if(!((GetCachedImageVisualProperty(Visual.Property.Type)?.Get(out visualType) ?? false) && visualType == (int)Visual.Type.AnimatedImage))
1378 // If ResourceUrl is not setuped, don't set property. fast return.
1379 if(string.IsNullOrEmpty(_resourceUrl))
1383 if (_border == null)
1385 PropertyValue image = new PropertyValue((int)Visual.Type.Image);
1386 cachedImagePropertyMap[Visual.Property.Type] = image;
1391 PropertyValue nPatch = new PropertyValue((int)Visual.Type.NPatch);
1392 cachedImagePropertyMap[Visual.Property.Type] = nPatch;
1394 PropertyValue border = new PropertyValue(_border);
1395 cachedImagePropertyMap[NpatchImageVisualProperty.Border] = border;
1400 if (backgroundExtraData != null && backgroundExtraData.CornerRadius != null)
1402 using (var cornerRadius = new PropertyValue(backgroundExtraData.CornerRadius))
1403 using (var cornerRadiusPolicy = new PropertyValue((int)backgroundExtraData.CornerRadiusPolicy))
1405 cachedImagePropertyMap[Visual.Property.CornerRadius] = cornerRadius;
1406 cachedImagePropertyMap[Visual.Property.CornerRadiusPolicy] = new PropertyValue((int)(backgroundExtraData.CornerRadiusPolicy));
1410 if (backgroundExtraData != null && backgroundExtraData.BorderlineWidth > 0.0f)
1412 using (var borderlineWidth = new PropertyValue(backgroundExtraData.BorderlineWidth))
1413 using (var borderlineColor = new PropertyValue(backgroundExtraData.BorderlineColor))
1414 using (var borderlineOffset = new PropertyValue(backgroundExtraData.BorderlineOffset))
1416 cachedImagePropertyMap[Visual.Property.BorderlineWidth] = borderlineWidth;
1417 cachedImagePropertyMap[Visual.Property.BorderlineColor] = borderlineColor;
1418 cachedImagePropertyMap[Visual.Property.BorderlineOffset] = borderlineOffset;
1422 // Do Fitting Buffer when desired dimension is set
1423 if (_desired_width != -1 && _desired_height != -1)
1425 if (_resourceUrl != null)
1427 Size2D imageSize = ImageLoader.GetOriginalImageSize(_resourceUrl, true);
1428 if( imageSize.Height > 0 && imageSize.Width > 0 && _desired_width > 0 && _desired_height > 0 )
1430 int adjustedDesiredWidth, adjustedDesiredHeight;
1431 float aspectOfDesiredSize = (float)_desired_height / (float)_desired_width;
1432 float aspectOfImageSize = (float)imageSize.Height / (float)imageSize.Width;
1433 if (aspectOfImageSize > aspectOfDesiredSize)
1435 adjustedDesiredWidth = _desired_width;
1436 adjustedDesiredHeight = imageSize.Height * _desired_width / imageSize.Width;
1440 adjustedDesiredWidth = imageSize.Width * _desired_height / imageSize.Height;
1441 adjustedDesiredHeight = _desired_height;
1444 PropertyValue returnWidth = new PropertyValue(adjustedDesiredWidth);
1445 cachedImagePropertyMap[ImageVisualProperty.DesiredWidth] = returnWidth;
1446 returnWidth?.Dispose();
1447 PropertyValue returnHeight = new PropertyValue(adjustedDesiredHeight);
1448 cachedImagePropertyMap[ImageVisualProperty.DesiredHeight] = returnHeight;
1449 returnHeight?.Dispose();
1450 PropertyValue scaleToFit = new PropertyValue((int)FittingModeType.ScaleToFill);
1451 cachedImagePropertyMap[ImageVisualProperty.FittingMode] = scaleToFit;
1452 scaleToFit?.Dispose();
1456 Tizen.Log.Fatal("NUI", "[ERROR] Can't use DesiredSize when ImageLoading is failed.");
1458 imageSize?.Dispose();
1466 /// Merge our collected properties, and set IMAGE property internally.
1468 private void UpdateImageMap()
1470 // Note : We can't use ImageView.Image property here. Because That property call UpdateImage internally.
1471 using(PropertyMap imageMap = new PropertyMap())
1473 using(PropertyValue returnValue = Tizen.NUI.Object.GetProperty(SwigCPtr, ImageView.Property.IMAGE))
1475 returnValue?.Get(imageMap);
1477 if(cachedImagePropertyMap != null)
1479 imageMap?.Merge(cachedImagePropertyMap);
1481 using(PropertyValue setValue = new PropertyValue(imageMap))
1483 SetProperty(ImageView.Property.IMAGE, setValue);
1486 // Update cached image property.
1487 MergeCachedImageVisualProperty(imageMap);
1492 /// Get image visual property by key.
1493 /// If we found value in local Cached result, return that.
1494 /// Else, get synced native map and return that.
1495 /// If there is no matched value, return null.
1497 [EditorBrowsable(EditorBrowsableState.Never)]
1498 protected virtual PropertyValue GetImageVisualProperty(int key)
1500 PropertyValue ret = GetCachedImageVisualProperty(key);
1503 // If we cannot find result form cached map, Get value from native engine.
1504 ret = Image?.Find(key);
1510 /// Get image visual property from NUI cached image map by key.
1511 /// If there is no matched value, return null.
1513 [EditorBrowsable(EditorBrowsableState.Never)]
1514 protected virtual PropertyValue GetCachedImageVisualProperty(int key)
1516 return cachedImagePropertyMap?.Find(key);
1520 /// Update NUI cached image visual property map by inputed property map.
1523 /// For performance issue, we will collect only "cachedImagePropertyKeyList" hold.
1525 [EditorBrowsable(EditorBrowsableState.Never)]
1526 protected virtual void MergeCachedImageVisualProperty(PropertyMap map)
1528 if(map == null) return;
1529 if(cachedImagePropertyMap == null)
1531 cachedImagePropertyMap = new PropertyMap();
1533 foreach(var key in cachedImagePropertyKeyList)
1535 PropertyValue value = map.Find(key);
1538 // Update-or-Insert new value
1539 cachedImagePropertyMap[key] = value;
1545 /// GetNaturalSize() should be guaranteed that ResourceUrl property setuped.
1546 /// So before get base.GetNaturalSize(), we should synchronous image properties
1548 internal override Vector3 GetNaturalSize()
1550 // Sync as current properties
1552 return base.GetNaturalSize();
1555 private void OnResourceLoaded(IntPtr view)
1557 ResourceLoadedEventArgs e = new ResourceLoadedEventArgs();
1558 e.Status = (ResourceLoadingStatusType)Interop.View.GetVisualResourceStatus(this.SwigCPtr, Property.IMAGE);
1560 if (_resourceLoadedEventHandler != null)
1562 _resourceLoadedEventHandler(this, e);
1567 /// Event arguments of resource ready.
1569 /// <since_tizen> 3 </since_tizen>
1570 public class ResourceReadyEventArgs : EventArgs
1575 /// The view whose resource is ready.
1577 /// <since_tizen> 3 </since_tizen>
1591 internal class ResourceLoadedEventArgs : EventArgs
1593 private ResourceLoadingStatusType status = ResourceLoadingStatusType.Invalid;
1594 public ResourceLoadingStatusType Status
1607 internal new class Property
1609 internal static readonly int IMAGE = Interop.ImageView.ImageGet();
1610 internal static readonly int PreMultipliedAlpha = Interop.ImageView.PreMultipliedAlphaGet();
1611 internal static readonly int PixelArea = Interop.ImageView.PixelAreaGet();
1614 private enum ImageType
1617 /// For Normal Image.
1622 /// For normal image, with synchronous loading and orientation correction property
1627 /// For nine-patch image
1632 private void OnBorderChanged(int x, int y, int width, int height)
1634 Border = new Rectangle(x, y, width, height);
1636 private void OnPixelAreaChanged(float x, float y, float z, float w)
1638 PixelArea = new RelativeVector4(x, y, z, w);
1641 private class ImageLayout : LayoutItem
1644 /// Gets or sets the mode to adjust view size to preserve the aspect ratio of the image resource.
1645 /// If this is set to be true, then the width or height, which is not set by user explicitly, can be adjusted to preserve the aspect ratio of the image resource.
1647 [EditorBrowsable(EditorBrowsableState.Never)]
1648 public bool AdjustViewSize
1652 return (Owner as ImageView)?.AdjustViewSize ?? false;
1656 if (Owner is ImageView imageView)
1658 imageView.AdjustViewSize = value;
1664 [EditorBrowsable(EditorBrowsableState.Never)]
1665 protected override void OnMeasure(MeasureSpecification widthMeasureSpec, MeasureSpecification heightMeasureSpec)
1667 // To not change the view size by DALi
1668 Owner.WidthResizePolicy = ResizePolicyType.Fixed;
1669 Owner.HeightResizePolicy = ResizePolicyType.Fixed;
1671 float specWidth = widthMeasureSpec.Size.AsDecimal();
1672 float specHeight = heightMeasureSpec.Size.AsDecimal();
1673 float naturalWidth = Owner.NaturalSize.Width;
1674 float naturalHeight = Owner.NaturalSize.Height;
1675 float minWidth = Owner.MinimumSize.Width;
1676 float maxWidth = Owner.MaximumSize.Width;
1677 float minHeight = Owner.MinimumSize.Height;
1678 float maxHeight = Owner.MaximumSize.Height;
1679 float aspectRatio = (naturalWidth > 0) ? (naturalHeight / naturalWidth) : 0;
1681 // Assume that the new width and height are given from the view's suggested size by default.
1682 float newWidth = Math.Min(Math.Max(naturalWidth, minWidth), (maxWidth < 0 ? Int32.MaxValue : maxWidth));
1683 float newHeight = Math.Min(Math.Max(naturalHeight, minHeight), (maxHeight < 0 ? Int32.MaxValue : maxHeight));
1685 // The width and height measure specs are going to be used to set measured size.
1686 // Mark that the measure specs are changed by default to update measure specs later.
1687 bool widthSpecChanged = true;
1688 bool heightSpecChanged = true;
1690 if (widthMeasureSpec.Mode == MeasureSpecification.ModeType.Exactly)
1692 newWidth = specWidth;
1693 widthSpecChanged = false;
1695 if (heightMeasureSpec.Mode != MeasureSpecification.ModeType.Exactly)
1697 if ((AdjustViewSize) && (aspectRatio > 0))
1699 newHeight = newWidth * aspectRatio;
1704 if (heightMeasureSpec.Mode == MeasureSpecification.ModeType.Exactly)
1706 newHeight = specHeight;
1707 heightSpecChanged = false;
1709 if (widthMeasureSpec.Mode != MeasureSpecification.ModeType.Exactly)
1711 if ((AdjustViewSize) && (aspectRatio > 0))
1713 newWidth = newHeight / aspectRatio;
1718 if (widthSpecChanged)
1720 widthMeasureSpec = new MeasureSpecification(new LayoutLength(newWidth), MeasureSpecification.ModeType.Exactly);
1723 if (heightSpecChanged)
1725 heightMeasureSpec = new MeasureSpecification(new LayoutLength(newHeight), MeasureSpecification.ModeType.Exactly);
1728 MeasuredSize.StateType childWidthState = MeasuredSize.StateType.MeasuredSizeOK;
1729 MeasuredSize.StateType childHeightState = MeasuredSize.StateType.MeasuredSizeOK;
1731 SetMeasuredDimensions(ResolveSizeAndState(new LayoutLength(newWidth), widthMeasureSpec, childWidthState),
1732 ResolveSizeAndState(new LayoutLength(newHeight), heightMeasureSpec, childHeightState));