Xamarin iOS subview created inside custom UIView class not showing up - uiview

I have a custom UIView class, where I would like to add a bunch of subviews. This should be a simple task but I can't seem to figure out why my views are not showing up on the UI.
The examples and tutorials out there are pretty straight forward and I believe I have implemented my code correctly. I have added a breakpoint at AddSubview and the container has a size.
The UIViewController class already has a background image added it via the storyboard.
Can someone help me see what I'm probably missing? I know it's something small.
Below is my code:
The custom view class
public class RotaryWheel : UIView
{
int numberOfSections;
public RotaryWheel(CGRect frame,int sections): base(frame)
{
numberOfSections = sections;
DrawWheel();
}
public void DrawWheel()
{
// derive the center x and y
float centerX = (float)(Frame.Width / 2);
float centerY = (float)(Frame.Height / 2);
container = new UIView();
container.Frame = new RectangleF(centerX, centerY, 100, 100);
container.BackgroundColor = UIColor.White;
AddSubview(container);
}
}
The UIViewController class where I initialize the view
public partial class HomePageController : UIViewController
{
public override void LoadView()
{
base.LoadView();
rotaryWheel = new RotaryWheel(new CGRect(20f, (float)(View.Frame.Height / 2), (float)View.Frame.Size.Width, (float)View.Frame.Height / 2f), 7);
View.AddSubview(rotaryWheel);
}
}

First at all, refer to loadView(). As the documentation mentioned
If you want to perform any additional initialization of your views, do so in the viewDidLoad() method.
We should never initialize subviews in LoadView, so I try to move that code to viewDidLoad
public override void ViewDidLoad()
{
base.ViewDidLoad();
RotaryWheel rotaryWheel = new RotaryWheel(new CGRect(20f, (float)(View.Frame.Height / 2), (float)View.Frame.Size.Width, (float)View.Frame.Height / 2f), 7);
View.AddSubview(rotaryWheel);
}
But it looks like this, the subviews doesn't locate as expected.
After moving that code to ViewDidAppear, the problem disappeared.
public override void ViewDidAppear(bool animated)
{
base.ViewDidAppear(animated);
if(rotaryWheel == null){
rotaryWheel = new RotaryWheel(new CGRect(20f, (float)(View.Frame.Height / 2), (float)View.Frame.Size.Width, (float)View.Frame.Height / 2f), 7);
View.AddSubview(rotaryWheel);
}
}
Summary:
The real size of View comes out in method ViewDidAppear. If you don't use autoLayout , you should manage the View Frame carefully.
And about why you didn't see the subview, I guess you selected the iphone4 ,iPhone 5 or iPhone5S simulator for test , the screen width is 320, you create RotaryWheel with X= 20 , centerX is 300 in method LoadView, so it is displayed out of screen.

Related

How to set width of XIB-View to displaywidth

I have my own xib-file looking like this:
Now I programmatically add multiple instances of this XIB-View to my original View which is a UIStackView with full width inside of a UIScrollView which takes the whole screen size.
I want to achieve, that every instance of my xib-view has the whole displayWidth. This is what I tried:
myView.frame.size = CGSize(myView.frame.size.height, view.frame.size.width())
But I can't change the view's width with this code. How do I achieve to change the width?
Edit: This is how I add the views (it is in java because I am using multi-os-engine but It is almost exactly like in objective-c)
#Override
#Selector("viewDidLoad")
public void viewDidLoad() {
UIView checkBox = instantiateFromNib("CheckBoxView");
for (UIView v : checkBox.subviews()) {
if (v instanceof DLRadioButton) {
((DLRadioButton) v).setTitleForState(option.getName(), UIControlState.Normal);
}
}
configView.addArrangedSubview(checkBox);
}
private UIView instantiateFromNib(String name) {
return (UIView) UINib.nibWithNibNameBundle(name, null).instantiateWithOwnerOptions(null, null).firstObject();
}

IOS 7.1 UICollectionView not recognising full click area for drag

I have a UICollectionView with
a custom layout that displays the items in a horizontal row
a custom UICollectionViewCell which contains a number of subviews - an image
and some labels.
Multiple instances of the UICollectionView are displayed vertically in a UITableView.
On iOS 8.1, all works well. Testing on iOS 7.1 though I can not drag the collection unless my finger is in the top third of the row (indicated by the yellow rectangle in the picture).
Note that the UITableView scrolls correctly vertically.
Any suggestions?
Thanks in advance, and apologies for the C#.
// The Layout
public sealed class SingleRowLayout : UICollectionViewFlowLayout
{
public SingleRowLayout()
{
this.ItemSize = new CGSize(50, 120); // 120 is the full cell height
this.ScrollDirection = UICollectionViewScrollDirection.Horizontal;
}
}
// The UICollectionViewCell
public sealed class StickerViewCell : UICollectionViewCell
{
[Export ("initWithFrame:")]
public StickerViewCell (CGRect frame) : base (frame)
{
var top = 0f;
this.imageView = new UIImageView();
this.imageView.ContentMode = UIViewContentMode.ScaleAspectFit;
this.imageView.Frame = new CGRect(
new CGPoint(GridDimensions.ImageInternalSidePadding, top),
new CGSize(GridDimensions.StickerWidth - (GridDimensions.ImageInternalSidePadding * 2), GridDimensions.StickerHeight)
);
top = (float)this.imageView.Frame.Height
this.sequenceTextView = this.createTextView(ref top);
this.dateTextView = this.createTextView(ref top);
this.sensationTextView = this.createTextView(ref top);
ContentView.AddSubview(this.imageView);
ContentView.AddSubview(this.sequenceTextView);
ContentView.AddSubview(this.sensationTextView);
ContentView.AddSubview(this.dateTextView);
}
private UILabel createTextView(ref float top)
{
var result = new UILabel();
result.AdjustsFontSizeToFitWidth = true;
result.Frame = new CGRect(
new CGPoint(2, top),
new CGSize(GridDimensions.StickerWidth - (2 * 2), GridDimensions.TextHeight)
);
top += GridDimensions.TextHeight + GridDimensions.TextFieldSpacing;
return result;
}
}

Autolayouts in UIScrollView using Cirrious.FluentLayouts.Touch

I've to do a ViewController with autolayouts in scrollView, but here is few problems:
public SomeVC() : UIViewController
{
_mainScrollView = new UIScrollView {
ShowsHorizontalScrollIndicator = false,
ShowsVerticalScrollIndicator = true,
BackgroundColor = UIColor.Clear,
ScrollEnabled = true,
AutoresizingMask = UIViewAutoresizing.FlexibleHeight,
TranslatesAutoresizingMaskIntoConstraints = true
};
_userDataTableView = new UITableView(CGRect.Empty, UITableViewStyle.Grouped);
_userDataTableView.LayoutIfNeeded();
_saveButton = new UIButton();
_menuTableView = new UITableView(CGRect.Empty, UITableViewStyle.Grouped);
_menuTableView.LayoutIfNeeded();
_logoutButton = new UIButton();
}
public override void LoadView()
{
base.LoadView();
View = _mainScrollView;
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
Add(_userDataTableView);
Add(_saveButton);
Add(_menuTableView);
Add(_logoutButton);
_mainScrollView.AddConstraints(
_userDataTableView.AtTopOf(View),
_userDataTableView.AtLeftOf(View),
_userDataTableView.AtRightOf(View),
_userDataTableView.Height().EqualTo(_userDataTableView.ContentSize.Height),
_saveButton.Below(_userDataTableView, 20),
_saveButton.AtLeftOf(_mainScrollView, 10),
_saveButton.AtRightOf(_mainScrollView, 10),
_saveButton.Height().EqualTo(44),
_menuTableView.Below(_saveButton, 20),
_menuTableView.AtLeftOf(_mainScrollView),
_menuTableView.AtRightOf(_mainScrollView),
_menuTableView.Height().EqualTo(_menuTableView.ContentSize.Height),
_logoutButton.Below(_menuTableView, 20),
_logoutButton.AtLeftOf(_mainScrollView, 10),
_logoutButton.AtRightOf(_mainScrollView, 10),
_logoutButton.Height().EqualTo(44)
);
_mainScrollView.SubviewsDoNotTranslateAutoresizingMaskIntoConstraints();
}
In fact, it works, but contents width is about half of screen width, and scrolling not working. How to get it works?
As far as I understand, the problem is - _mainScrollView.ContentSize, but how and where should I set it, when using autolayouts?
If your views doesn't exceed the screen you will not be able to do scroll. if you only have something like this :
// Create containers
contentView = new UIView();
scrollView = new UIScrollView { contentView };
Add(scrollView);
contentView.AddSubviews(logo, user, password, loginButton);
// Auto layout
View.SubviewsDoNotTranslateAutoresizingMaskIntoConstraints();
View.AddConstraints(scrollView.FullWidthOf(View));
View.AddConstraints(scrollView.FullHeightOf(View));
View.AddConstraints(
contentView.WithSameWidth(View),
contentView.WithSameHeight(View).SetPriority(UILayoutPriority.DefaultLow)
);
scrollView.SubviewsDoNotTranslateAutoresizingMaskIntoConstraints();
scrollView.AddConstraints(contentView.FullWidthOf(scrollView));
scrollView.AddConstraints(contentView.FullHeightOf(scrollView));
// very important to make scrolling work
var bottomViewConstraint = contentView.Subviews.Last()
.AtBottomOf(contentView).Minus(20);
contentView.SubviewsDoNotTranslateAutoresizingMaskIntoConstraints();
contentView.AddConstraints(
logo.AtTopOf(contentView),
logo.WithRelativeWidth(contentView, 0.8f),
logo.WithSameCenterX(contentView),
logo.WithRelativeHeight(contentView, 0.3f),
user.Below(logo, 50),
user.WithRelativeWidth(logo, 0.8f),
user.WithSameCenterX(logo),
password.Below(user),
password.WithSameWidth(user),
password.WithSameCenterX(user),
loginButton.Below(password, 50),
loginButton.WithRelativeWidth(password, 0.9f),
loginButton.Height().EqualTo(50),
loginButton.WithSameCenterX(password)
);
contentView.AddConstraints(bottomViewConstraint);
}
I'm using this package and it works perfectly like if I was using a stackLayout inside a scrollview in xamarin.forms I think is the perfect behaviour.
Xamarin.IQKeyboardManager from Nuget
Also, if you want to center your content view inside the scrollview you will need to add this:
public override void ViewWillLayoutSubviews()
{
base.ViewWillLayoutSubviews();
var scrollViewBounds = scrollView.Bounds;
var containerViewBounds = contentView.Bounds;
var scrollViewInsets = UIEdgeInsets.Zero;
scrollViewInsets.Top = scrollViewBounds.Size.Height / 2.0f;
scrollViewInsets.Top -= contentView.Bounds.Size.Height / 2.0f;
scrollViewInsets.Bottom = scrollViewBounds.Size.Height / 2.0f;
scrollViewInsets.Bottom -= contentView.Bounds.Size.Height / 2.0f;
scrollViewInsets.Bottom += 1;
scrollView.ContentInset = scrollViewInsets;
}
And thats all, doesn't matter how your contentView is . You will have a centered contetnview inside a scrollview and a manager to capture the keyboard events and adapt your view to this event .
Solution found:
Firstly:
_userDataTableView.AtLeftOf(View),
_userDataTableView.AtRightOf(View),
is not valid, instead of this, we should use:
_userDataTableView.AtLeftOf(View),
_userDataTableView.WithSameWidth(View),
if we want margin, we just add
_userDataTableView.WithSameWidth(View).Minus(MARGIN)
And the last thing we have to do:
_logoutButton.Height().EqualTo(44),
_logoutButton.Bottom().EqualTo().BottomOf(_mainScrollView).Plus(10)
last line is very important. It says to scrollView right content size.

Can't get UITableView to scroll inside my SlidingPanel

I've got a UITableView located in a View attached to a SlidingPanel.
I'm using SlidingPanels.Lib, and I've got a custom presenter
Here's a gist of the custom presenter
From there my MenuView is really straight forward.
public class MenuView : ViewControllerBase
{
private new MenuViewModel ViewModel { get { return (MenuViewModel)base.ViewModel; } }
public override void ViewDidLoad()
{
base.ViewDidLoad();
// todo: this should actually be...
// _currentBookId = currentUser.UserBooks[0].BookId;
// _homeViewModel.ChapterViewModel = Mvx.Resolve<IChapterService>().FindByBookId(_currentBookId);
ViewModel.Chapters = Mvx.Resolve<IChapterService>().Find();
// this ensures the sliding panel doesn't fill the entire view.
var frame = View.Frame;
frame.Width = 300;
View.Frame = frame;
// var currentUser = Mvx.Resolve<IUserService>().GetById(Mvx.Resolve<UserModel>().Id);
var label = new UILabel(new RectangleF(10, 10, 300, 40))
{
TextColor = UIColor.White,
};
Add(label);
//var listHeight = (chapters.Count*40);
var navigationList = new UITableView(new RectangleF(0, 50, 300, 300))
{
Source = new NavigationTableSource(ViewModel.Chapters)
};
Add(navigationList);
var set = this.CreateBindingSet<MenuView, MenuViewModel>();
set.Bind(label).To(vm => vm.DisplayName);
set.Apply();
}
}
Unfortunately I'm not sure where to look in order to allow the TableView to scroll. I can see it, but it goes beyond the bottom of the screen.
I think the problem is in:
var listHeight = (chapters.Count*40);
Instead of this, try setting the height to the height of the available screen (which depends on which iPhone/iPad you are on). After this, then the list will scroll within that available height.
Took a couple of hours of dicking around to discover that the original source code that I grabbed from #patbonecrusher's Github repo had some differences from the lib that you can find at #fcaico's Github repo
Long story short... all I had to do was compile #fcaico's version and deploy it into my app, and the scrolling came back. Now I realize that #fcaico's repo just contains a submodule to #patbonecrusher's, but for some reason... the recompile fixed the issue. Don't have a lot of time to dig into the reason why.

How to hide a UIView and remove the "empty" space? -iOS/Monotouch

I need to be able to hide controls on a page that uses constraints and remove the empty space that Hidden=true leaves. It needs to be similar to how the web handles visibility. If it's invisible, it doesn't take up space.
Does anyone know of a clean way to accomplish this?
Please let me know if you need more details.
Thx
Example:
UIButton | UIButton | UIButton
"empty space for hidden UIButton"
UIButton
That should really be rendered like this:
UIButton | UIButton | UIButton
UIButton
Edit: I'm using Xamarin Studio and VS2012 for development.
Since original question is related to Xamarin, I provide complete C# solution.
First, create height constraint for your view and give it an identifier in Xcode Interface Builder:
Then in controller override ViewDidAppear() method and wrap view with HidingViewHolder:
public override void ViewDidAppear(bool animated)
{
base.ViewDidAppear(animated);
applePaymentViewHolder = new HidingViewHolder(ApplePaymentFormView, "ApplePaymentFormViewHeightConstraint");
}
It is important to create HidingViewHolder when view was laid out, so it has real height assigned.
To hide or show view you can use corresponding methods:
applePaymentViewHolder.HideView();
applePaymentViewHolder.ShowView();
HidingViewHolder source:
using System;
using System.Linq;
using UIKit;
/// <summary>
/// Helps to hide UIView and remove blank space occupied by invisible view
/// </summary>
public class HidingViewHolder
{
private readonly UIView view;
private readonly NSLayoutConstraint heightConstraint;
private nfloat viewHeight;
public HidingViewHolder(UIView view, string heightConstraintId)
{
this.view = view;
this.heightConstraint = view
.GetConstraintsAffectingLayout(UILayoutConstraintAxis.Vertical)
.SingleOrDefault(x => heightConstraintId == x.GetIdentifier());
this.viewHeight = heightConstraint != null ? heightConstraint.Constant : 0;
}
public void ShowView()
{
if (!view.Hidden)
{
return;
}
if (heightConstraint != null)
{
heightConstraint.Active = true;
heightConstraint.Constant = viewHeight;
}
view.Hidden = false;
}
public void HideView()
{
if (view.Hidden)
{
return;
}
if (heightConstraint != null)
{
viewHeight = heightConstraint.Constant;
heightConstraint.Active = true;
heightConstraint.Constant = 0;
}
view.Hidden = true;
}
}
In storyboard wire your constrains first. Then try this
self.viewToHideHeight.constant = 0;
self.lowerButtonHeightFromTop.constant = self.viewToHideHeightFromTop.constant + self.viewToHideHeight.constant;
[UIView animateWithDuration:0.5f animations:^{
self.viewToHide.alpha = 0.0f;
[self.view layoutIfNeeded];
}];

Resources