Created
October 24, 2015 16:43
-
-
Save marcinkuptel/85435f988d444390f20a to your computer and use it in GitHub Desktop.
ProxyView - Advanced UI with Xamarin.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 System; | |
using System.Collections.Generic; | |
using UIKit; | |
using CoreGraphics; | |
using Foundation; | |
namespace iOS | |
{ | |
public class ProxyView: UIView | |
{ | |
enum SubviewTag { | |
Container = 1, | |
Content | |
} | |
UIScrollView ParentScrollView { get; set; } | |
UIView ParentContainerView { get; set; } | |
List<UIScrollView> ScrollViews { get; set; } | |
List<int> _contentHeights; | |
public List<int> ContentHeights { | |
get { | |
return _contentHeights; | |
} | |
set { | |
if(_contentHeights == null) { | |
_contentHeights = value; | |
} else { | |
if(value.Count != _contentHeights.Count) { | |
_contentHeights = value; | |
ReloadScrollViews(); | |
}else{ | |
_contentHeights = value; | |
UpdateContentHeights(); | |
} | |
} | |
} | |
} | |
int HeaderHeight { get; set; } | |
int _pageIndex; | |
public int PageIndex { | |
get { | |
return _pageIndex; | |
} | |
set { | |
_pageIndex = value; | |
SetNeedsLayout(); | |
} | |
} | |
WeakReference<IProxyViewDelegate> _proxyDelegate; | |
IProxyViewDelegate ProxyDelegate { | |
get { | |
IProxyViewDelegate proxyDelegate; | |
_proxyDelegate.TryGetTarget(out proxyDelegate); | |
return proxyDelegate; | |
} | |
set { | |
_proxyDelegate = new WeakReference<IProxyViewDelegate>(value); | |
} | |
} | |
public ProxyView (IProxyViewDelegate proxyDelegate, List<int> contentHeights, int headerHeight) | |
{ | |
HeaderHeight = headerHeight; | |
ScrollViews = new List<UIScrollView>(); | |
ContentHeights = contentHeights; | |
ProxyDelegate = proxyDelegate; | |
SetUpHierarchy(); | |
} | |
public override void LayoutSubviews() | |
{ | |
base.LayoutSubviews(); | |
SetPage(PageIndex); | |
} | |
void SetUpHierarchy() | |
{ | |
AddParentScrollView(); | |
AddParentContainerView(); | |
AddChildScrollViews(); | |
} | |
void AddParentScrollView() | |
{ | |
ParentScrollView = new UIScrollView(); | |
ParentScrollView.PagingEnabled = true; | |
ParentScrollView.TranslatesAutoresizingMaskIntoConstraints = false; | |
ParentScrollView.ShowsHorizontalScrollIndicator = false; | |
var tap = new UITapGestureRecognizer(); | |
tap.AddTarget(() => { | |
var loc = tap.LocationInView(this); | |
ProxyDelegate.ProxyTappedAtLocation(this, loc); | |
}); | |
AddGestureRecognizer(tap); | |
var weak = new WeakReference<ProxyView>(this); | |
ParentScrollView.Scrolled += (sender, e) => { | |
ProxyView weakProxy; | |
weak.TryGetTarget(out weakProxy); | |
_pageIndex = weakProxy.CurrentPageIndex(); | |
ProxyDelegate.ParentScrollViewDidScroll(ParentScrollView.ContentOffset.X); | |
}; | |
AddSubview(ParentScrollView); | |
var views = new NSDictionary("parent", ParentScrollView); | |
var parentVConstraints = NSLayoutConstraint.FromVisualFormat("V:|[parent]|", 0, null, views); | |
var parentHConstraints = NSLayoutConstraint.FromVisualFormat("H:|[parent]|", 0, null, views); | |
AddConstraints(parentVConstraints); | |
AddConstraints(parentHConstraints); | |
} | |
void AddParentContainerView() | |
{ | |
ParentContainerView = new UIView(); | |
ParentContainerView.TranslatesAutoresizingMaskIntoConstraints = false; | |
var containerViews = new NSDictionary("container", ParentContainerView); | |
ParentScrollView.AddSubview(ParentContainerView); | |
var containerVConstraints = NSLayoutConstraint.FromVisualFormat("V:|[container]|", 0, null, containerViews); | |
var containerHConstraints = NSLayoutConstraint.FromVisualFormat("H:|[container]|", 0, null, containerViews); | |
var top = NSLayoutConstraint.Create(ParentContainerView, NSLayoutAttribute.Top, NSLayoutRelation.Equal, this, NSLayoutAttribute.Top, 1, 0); | |
var bottom = NSLayoutConstraint.Create(ParentContainerView, NSLayoutAttribute.Bottom, NSLayoutRelation.Equal, this, NSLayoutAttribute.Bottom, 1, 0); | |
ParentScrollView.AddConstraints(containerVConstraints); | |
ParentScrollView.AddConstraints(containerHConstraints); | |
AddConstraint(top); | |
AddConstraint(bottom); | |
} | |
void AddChildScrollViews() | |
{ | |
for(int i = 0; i < ContentHeights.Count; i++) | |
{ | |
int height = ContentHeights[i]; | |
var scrollView = AddChildScrollView(i); | |
var container = AddChildContainerView(scrollView, height); | |
AddChildContentView(container, height); | |
} | |
AddScrollViewConstraints(); | |
} | |
UIScrollView AddChildScrollView(int index) | |
{ | |
var scrollView = new UIScrollView(); | |
scrollView.TranslatesAutoresizingMaskIntoConstraints = false; | |
ScrollViews.Add(scrollView); | |
ParentContainerView.AddSubview(scrollView); | |
scrollView.Scrolled += (sender, e) => { | |
if(scrollView.ContentOffset.Y <= HeaderHeight) { | |
foreach(UIScrollView s in ScrollViews) { | |
if(s != scrollView) { | |
var newOffset = new CGPoint(s.ContentOffset.X, scrollView.ContentOffset.Y); | |
s.Bounds = new CGRect(newOffset, s.Bounds.Size); | |
} | |
} | |
} | |
ProxyDelegate.ScrollViewDidScroll(index, scrollView.ContentOffset.Y); | |
}; | |
var width = NSLayoutConstraint.Create(scrollView, NSLayoutAttribute.Width, NSLayoutRelation.Equal, this, NSLayoutAttribute.Width, 1, 0); | |
var height = NSLayoutConstraint.Create(scrollView, NSLayoutAttribute.Height, NSLayoutRelation.Equal, ParentContainerView, NSLayoutAttribute.Height, 1, 0); | |
AddConstraint(width); | |
ParentContainerView.AddConstraint(height); | |
return scrollView; | |
} | |
UIView AddChildContainerView(UIScrollView childScrollView, int height) | |
{ | |
var containerView = new UIView(); | |
containerView.Tag = (int)SubviewTag.Container; | |
containerView.TranslatesAutoresizingMaskIntoConstraints = false; | |
childScrollView.AddSubview(containerView); | |
var containerViews = new NSDictionary("container", containerView); | |
var containerVConstraints = NSLayoutConstraint.FromVisualFormat("V:|[container]|", 0, null, containerViews); | |
var containerHConstraints = NSLayoutConstraint.FromVisualFormat("H:|[container]|", 0, null, containerViews); | |
childScrollView.AddConstraints(containerVConstraints); | |
childScrollView.AddConstraints(containerHConstraints); | |
return containerView; | |
} | |
void AddChildContentView(UIView containerView, int height) | |
{ | |
var content = new UIView(); | |
content.Tag = (int)SubviewTag.Content; | |
content.TranslatesAutoresizingMaskIntoConstraints = false; | |
containerView.AddSubview(content); | |
var leftContentWidth = NSLayoutConstraint.Create(content, NSLayoutAttribute.Width, NSLayoutRelation.Equal, this, NSLayoutAttribute.Width, 1, 0); | |
var leftContentHeight = NSLayoutConstraint.Create(content, NSLayoutAttribute.Height, NSLayoutRelation.Equal, null, NSLayoutAttribute.NoAttribute, 1, height); | |
var contentView = new NSDictionary("content", content); | |
var vertical = NSLayoutConstraint.FromVisualFormat("V:|[content]|", 0, null, contentView); | |
var horizontal = NSLayoutConstraint.FromVisualFormat("H:|[content]|", 0, null, contentView); | |
containerView.AddConstraints(vertical); | |
containerView.AddConstraints(horizontal); | |
AddConstraint(leftContentWidth); | |
containerView.AddConstraint(leftContentHeight); | |
} | |
void AddScrollViewConstraints() | |
{ | |
for(int i = 1; i < ScrollViews.Count; i++) | |
{ | |
var left = ScrollViews[i - 1]; | |
var right = ScrollViews[i]; | |
var scrollViews = new NSDictionary("left", left, "right", right); | |
var constraints = NSLayoutConstraint.FromVisualFormat("H:[left][right]", 0, null, scrollViews); | |
ParentContainerView.AddConstraints(constraints); | |
} | |
var leftConstraint = NSLayoutConstraint.FromVisualFormat("H:|[scrollView]", 0, null, new NSDictionary("scrollView", ScrollViews[0])); | |
ParentContainerView.AddConstraints(leftConstraint); | |
var last = ScrollViews[ScrollViews.Count - 1]; | |
var rightConstraint = NSLayoutConstraint.FromVisualFormat("H:[scrollView]|", 0, null, new NSDictionary("scrollView", last)); | |
ParentContainerView.AddConstraints(rightConstraint); | |
} | |
void UpdateContentHeights() | |
{ | |
for(int i = 0; i < ScrollViews.Count; i++) | |
{ | |
var sv = ScrollViews[i]; | |
var height = ContentHeights[i]; | |
var container = sv.ViewWithTag((int)SubviewTag.Container); | |
var content = container.ViewWithTag((int)SubviewTag.Content); | |
content.RemoveFromSuperview(); | |
AddChildContentView(container, height); | |
} | |
} | |
void ReloadScrollViews() | |
{ | |
foreach(UIScrollView s in ScrollViews){ | |
s.RemoveFromSuperview(); | |
} | |
ScrollViews.Clear(); | |
AddChildScrollViews(); | |
} | |
#region - | |
void SetPage(int index) | |
{ | |
if(index != CurrentPageIndex()) { | |
var location = new CGPoint(index * ParentScrollView.Frame.Size.Width, ParentScrollView.Bounds.Location.Y); | |
ParentScrollView.Bounds = new CGRect(location, ParentScrollView.Bounds.Size); | |
} | |
} | |
int CurrentPageIndex() | |
{ | |
return (int)((ParentScrollView.ContentOffset.X + ParentScrollView.Frame.Size.Width / 2) | |
/ ParentScrollView.Frame.Size.Width); | |
} | |
#endregion | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment