Last active
November 8, 2018 20:26
-
-
Save paul-kiar/4ca352a3add70d548742291441dc9873 to your computer and use it in GitHub Desktop.
CarouselViewRendererFix for iOS
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using CoreGraphics; | |
using System; | |
using System.Reflection; | |
using UIKit; | |
using Xamarin.Forms; | |
using Xamarin.Forms.Platform.iOS; | |
[assembly: ExportRenderer(typeof(CarouselView), typeof(YourNameSpace.iOS.Renderers.CarouselViewRendererFix))] | |
namespace YourNameSpace.iOS.Renderers | |
{ | |
// this is an implementation of this pull request: https://github.com/xamarin/Xamarin.Forms.CarouselView/pull/13/files | |
public class CarouselViewRendererFix : Xamarin.Forms.Platform.CarouselViewRenderer | |
{ | |
private CGRect? _lastBounds; | |
private UICollectionViewController _controller = null; | |
private MethodInfo _controllerReloadDataMethod = null; | |
private MethodInfo _controllerScrollToPositionMethod = null; | |
private Type _controllerType = null; | |
/// <summary> | |
/// The underlying controller of the view | |
/// </summary> | |
protected UICollectionViewController Controller | |
{ | |
get | |
{ | |
if (_controller == null) | |
{ | |
FieldInfo fi = typeof(Xamarin.Forms.Platform.CarouselViewRenderer).GetField(nameof(_controller), BindingFlags.NonPublic | BindingFlags.Instance); | |
object cvc = fi?.GetValue(this); | |
_controller = (UICollectionViewController)cvc; | |
} | |
return _controller; | |
} | |
} | |
/// <summary> | |
/// The underlying controller has an internal type, so I have to get it by reflection | |
/// </summary> | |
protected Type ControllerType | |
{ | |
get | |
{ | |
if (_controllerType == null) | |
{ | |
_controllerType = Controller?.GetType(); | |
} | |
return _controllerType; | |
} | |
} | |
/// <summary> | |
/// The method that reloads the data on the Controller, it is an internal method so I have to get it by reflection | |
/// </summary> | |
protected MethodInfo ControllerReloadDataMethod | |
{ | |
get | |
{ | |
if (_controllerReloadDataMethod == null) | |
{ | |
_controllerReloadDataMethod = ControllerType?.GetMethod(nameof(ReloadData), BindingFlags.Instance | BindingFlags.NonPublic); | |
} | |
return _controllerReloadDataMethod; | |
} | |
} | |
/// <summary> | |
/// The method that scrolls to position on the Controller, it is an internal method so I have to get it by reflection | |
/// </summary> | |
protected MethodInfo ControllerScrollToPositionMethod | |
{ | |
get | |
{ | |
if (_controllerScrollToPositionMethod == null) | |
{ | |
_controllerScrollToPositionMethod = ControllerType?.GetMethod(nameof(ScrollToPosition), BindingFlags.Instance | BindingFlags.NonPublic); | |
} | |
return _controllerScrollToPositionMethod; | |
} | |
} | |
/// <summary> | |
/// Reload the data in the controller | |
/// </summary> | |
/// <param name="position">current position in the data</param> | |
protected void ReloadData(int position) | |
{ | |
var parameters = new object[1]; | |
parameters[0] = position; | |
ControllerReloadDataMethod?.Invoke(Controller, parameters); | |
} | |
/// <summary> | |
/// Scroll to a position on the controller | |
/// </summary> | |
/// <param name="position">position to scroll to</param> | |
/// <param name="animate">show animations when scrolling</param> | |
protected void ScrollToPosition(int position, bool animate) | |
{ | |
var parameters = new object[2]; | |
parameters[0] = position; | |
parameters[1] = animate; | |
ControllerScrollToPositionMethod?.Invoke(Controller, parameters); | |
} | |
/// <summary> | |
/// This override will adjust the layout on rotation (code in the base implementation doesn't work) | |
/// </summary> | |
public override void LayoutSubviews() | |
{ | |
bool? wasPortrait = null; | |
if ( _lastBounds != null ) | |
{ | |
wasPortrait = _lastBounds.Value.Height > _lastBounds.Value.Width; | |
} | |
base.LayoutSubviews(); | |
var nowPortrait = Bounds.Height > Bounds.Width; | |
if ( wasPortrait == null || wasPortrait != nowPortrait ) | |
{ | |
ScrollToPosition(Element.Position, false); | |
} | |
_lastBounds = Bounds; | |
} | |
/// <summary> | |
/// This forces reload of the data when the Element Changes | |
/// </summary> | |
/// <param name="e"></param> | |
protected override void OnElementChanged(ElementChangedEventArgs<CarouselView> e) | |
{ | |
base.OnElementChanged(e); | |
if (e.NewElement != null) | |
{ | |
ReloadData(Element.Position); | |
} | |
} | |
/// <summary> | |
/// Cleans up the controller and control | |
/// </summary> | |
/// <param name="disposing"></param> | |
protected override void Dispose(bool disposing) | |
{ | |
var control = Control; | |
base.Dispose(disposing); | |
if ( disposing ) | |
{ | |
if( Controller != null) | |
{ | |
Controller.Dispose(); | |
} | |
if (control != null) | |
{ | |
control.Dispose(); | |
} | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment