I have need to modify and customize the Entry Control in Xamarin, but I have difficulty setting, or rather to find the method for declaring the height of the control of Xamarin ios.
How can I do ? here is my code.
[assembly: ExportRenderer(typeof(MyEntry), typeof(MyEntryRenderer))]
namespace MyApplication.iOS
{
public class MyEntryRenderer : EntryRenderer
{
//CUSTOM entry RENDER IOS
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);
if (Control != null)
{
Control.BackgroundColor = UIColor.FromRGB(43, 50, 58);
Control.TextColor = UIColor.FromRGB(255, 255, 255);
//Control.Height ???
}
}
}
}
There's a HeightRequest property on the cross-platform Entry class. Why not set it there and let Xamarin's renderer do the work?
If you want to set it directly in your own renderer try
Control.Frame = new CGRect(0, 0, width, height);
You can set this on PCL/shared side.
public MyEntry()
{
this.HeightRequest = 50;
}
Related
I added an RoutingEffect in Xamarin Form project and PlatformEffect in my Xamarin.iOS project. It will add effect to Stacklayout. The Stacklayout in this demo is a custom navigation bar. The below of navigation bar is a scrollview has many cells (label, entry, picker).
I implemented in Android is OK.
But in iOS has problem: Shadow effect cannot overlays some controls, such as: Entry, Editor, Picker. Could you share me how to fix it?
This is code in Xamarin.iOS project.
public class DropShadowEffect : PlatformEffect
{
protected override void OnAttached()
{
try
{
var effect = (myDemo.UIControls.DropShadowEffect)Element.Effects.FirstOrDefault(e => e is myDemo.UIControls.DropShadowEffect);
if (effect != null)
{
Container.Layer.CornerRadius = effect.Radius;
Container.Layer.ShadowColor = UIColor.Red.CGColor;// effect.Color.ToCGColor();
Container.Layer.ShadowOffset = new CGSize(effect.DistanceX, effect.DistanceY);
Container.Layer.ShadowOpacity = 0.8f;
Container.Layer.ShadowRadius = 2f;
Container.Layer.ShouldRasterize = true;
Container.Layer.MasksToBounds = false;
}
}
catch (Exception ex)
{
Console.WriteLine("Cannot set property on attached control. Error: {0}", ex.Message);
}
}
*Shadow effect overly Label is OK
*Shadow effect cannot overlay either Picker or Entry
Cause:
Actually, such as Label will still overlay the shadow.But it doesn't seem obvious.If you set the background of label (such as red ),you will see the overlay.
Solution:
You can set the BackgroundColor of the Picker and Entry in the custom renderer to let the alpha as 0.
For example in EntryRenderer
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);
if (Control != null)
{
Control.BackgroundColor = new UIColor(1,1,1,0);//The last parameter sets the alpha of backgound as transparent
Control.Layer.MasksToBounds = true;
Control.Layer.CornerRadius = xxx; //set the rounded corner
Control.Layer.BorderColor = UIColor.xxx.CGColor;
Control.Layer.BorderWidth = xxx;
}
}
Stuart's N-06 Books sample is good for getting basic understanding about using MvxSimpleTableViewSource.
[Register("FirstView")]
public class FirstView : MvxViewController
{
public override void ViewDidLoad()
{
View = new UIView(){ BackgroundColor = UIColor.White};
base.ViewDidLoad();
// ios7 layout
if (RespondsToSelector(new Selector("edgesForExtendedLayout")))
EdgesForExtendedLayout = UIRectEdge.None;
var textField = new UITextField(new RectangleF(10, 10, 300, 40));
Add(textField);
var tableView = new UITableView(new RectangleF(0, 50, 320, 500), UITableViewStyle.Plain);
Add(tableView);
tableView.RowHeight = 88;
var source = new MvxSimpleTableViewSource(tableView, BookCell.Key, BookCell.Key);
tableView.Source = source;
var set = this.CreateBindingSet<FirstView, Core.ViewModels.FirstViewModel>();
set.Bind(textField).To(vm => vm.SearchTerm);
set.Bind(source).To(vm => vm.Results);
set.Apply();
tableView.ReloadData();
}
}
But how can resize the tableview's height according it's content once it loads data?
Not entirely sure what you want to do... Normally in an iOS UI, the tableview size is fixed regardless of its content.
However, if you did want to resize the table then you could:
Inherit from MvxTableViewSource or UITableView and provide some logic there
Or add a binding in your class to some View property TableCount, bind that property and then implement the sizing logic there. Something like:
set.Bind(this).For(v => v.TableCount).To(vm => vm.Results.Count);
private int _tableCount
public int TableCount {
get { return _tableCount; }
set {
// implement your sizing animations here (maybe animate constraints?)
}
}
Just to add to Stuart's answer, here is an example for the frame of the table:
int _tableHeight;
public int TableHeight
{
get { return _tableHeight; }
set
{
_tableHeight = value;
_myPlayers.Frame = _tableHeight > 0 ? new CGRect(0, 0, UIScreen.MainScreen.Bounds.Width, Dimens.TableRowHeight * _tableHeight) : new CGRect(0, 0, UIScreen.MainScreen.Bounds.Width, Dimens.TableRowHeight * BusinessConstants.GetBiggestPositionCount());
_myPlayers.ReloadData();
}
}
I would like to know how to bind the UIProgressView's Progress property.
Having this in the design:
[Outlet]
MonoTouch.UIKit.UIProgressView ProgressIndicator { get; set; }
I've tried the following:
set.Bind(ProgressIndicator).For(p => p.Progress).To(vm => vm.IosProgress);
set.Bind(ProgressIndicator).For("Progress").To(vm => vm.IosProgress);
In the ViewModel I have:
private float _iosProgress;
public float IosProgress
{
get { return _iosProgress; }
set { _iosProgress = value; RaisePropertyChanged(()=>IosProgress); }
}
UPDATE AS REQUESTED:
- I have an iPhone 4 with iOS7.
- I have tried to bind the IosProgress indicator to a Label, works perfectly, having tested with 3 values, 0.33333, 0,666667 and 1 showing in the label.
I created two screen captures for you.
This is showing the value of the IosProgress indicator during debug with initial value given in constructor as 0.1f, also the debug message.
This is showing the 3 versions I've tried, having the same faulty results, debug message for the current one:
Thank you!
I just tried the SeekView in https://github.com/MvvmCross/MvvmCross-Tutorials/tree/master/ApiExamples with a UIProgressView like:
public override void ViewDidLoad()
{
base.ViewDidLoad();
var label = new UILabel(new RectangleF(10, 100, 100, 30));
label.Text = "Slide me:";
Add(label);
var seek = new UISlider(new RectangleF(110, 100, 200, 30));
seek.MinValue = 0;
seek.MaxValue = 100;
Add(seek);
var pro = new UIProgressView(new RectangleF(110, 130, 200, 30));
Add(pro);
var set = this.CreateBindingSet<SeekView, SeekViewModel>();
set.Bind(seek).To(vm => vm.SeekProperty);
set.Bind(pro).For(v => v.Progress).To("SeekProperty / 100");
set.Apply();
}
This worked exactly as expected on an iOS7 iPhone simulator.
The only problem I had was if the ViewModel property went outside the 0.0f to 1.0f range.
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];
}];
I'm currently trying to create a custom navigation-bar for my navigation-controller in iOS using MonoTouch. The application I'm developing has the need to have a single string available on-screen no matter where you are on the application, and I wan't to achieve something like this (I know this is a little out off proportion, but you should be able to get the point):
+-----------------------------------------+
| /---------| +---+ |
| / Back | Controller Name |btn| |
| \---------| +---+ |
+-----------------------------------------+
| Current building <- global string |
+-----------------------------------------+
The bottom bar should be as small as possible (while not being hard to read), and the original navigation-bar might need to be a tiny bit smaller than normal.
Also, I've tried not to use the designer, but to write all the UI-code myself, but if that is impossible to achieve this, then I'll off cause have to use the designer. Currently I've found a project for creating a custom UINavigationBar in MonoTouch, but I have no idea of how to apply that to my NavigationController (see as the NavigationBar-property is read-only). The project I was talking about can be found here: https://github.com/mafis/Monotouch-Custom-Control/tree/master/CustomControls. Also, I would like the design of the actual navigationbar (the top part) to be standard iOS design, and work as a navigationbar normally would.
Any hints, or pointers at how to do this would be appreciated.
This is how I ended up solving this problem. I subclassed UIViewController like this:
using System;
using MonoTouch.UIKit;
using MonoTouch.CoreGraphics;
using System.Drawing;
using System.Collections.Generic;
using FdvWeb.Core;
namespace FdvWeb
{
[MonoTouch.Foundation.Preserve(AllMembers=true)]
public class MainNavigationController : UINavigationController
{
private const float NAV_BAR_HEIGHT = 44;
private readonly float buildingBarTop = 44;
private readonly float buildingBarHeight = 17;
private readonly float viewOffset;
private readonly HashSet<UIViewController> modifiedViewControllers = new HashSet<UIViewController>();
UITextView buildingTextView;
[MonoTouch.Foundation.Preserve]
public MainNavigationController ()
{
viewOffset = buildingBarTop + buildingBarHeight - NAV_BAR_HEIGHT;
var tt = new UITextView (new RectangleF (0, buildingBarTop, 320, buildingBarHeight));
NavigationBarHidden = false;
NavigationBar.AddSubview (tt);
tt.Font = UIFont.BoldSystemFontOfSize (12);
tt.TextAlignment = UITextAlignment.Center;
tt.TextColor = UIColor.LightTextColor;
tt.BackgroundColor = UIColor.ViewFlipsideBackgroundColor;
tt.Editable = false;
tt.ContentInset = new UIEdgeInsets (-9, 0, 0, 0);
buildingTextView = tt;
}
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
}
public override void ViewWillAppear (bool animated)
{
base.ViewWillAppear (animated);
}
public string BuildingText
{
get {
return buildingTextView.Text;
}
set {
container.Resolve<IUIThreadDispatcher> ().DispatchOnUIThread (delegate { // Run on UI thread
buildingTextView.Text = value;
});
}
}
public override void PushViewController (UIViewController viewController, bool animated)
{
if (!modifiedViewControllers.Contains (viewController))
{
viewController.View = new PaddedView (viewController.View, new InnsetF (0, viewOffset, 0, 0));
modifiedViewControllers.Add (viewController);
}
viewController.NavigationItem.RightBarButtonItem = pickBuildingItem;
base.PushViewController (viewController, animated);
}
private class PaddedView : UIView
{
private UIView view;
private InnsetF innsets;
public PaddedView (UIView view, InnsetF innsets)
: base(view.Frame)
{
this.view = view;
this.innsets = innsets;
this.AutoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleHeight;
this.AddSubview (view);
}
public override void LayoutSubviews ()
{
//apply the insets to the subview
view.Frame = new RectangleF (innsets.Left, innsets.Top,
Frame.Size.Width - innsets.Left - innsets.Right,
Frame.Size.Height - innsets.Top - innsets.Bottom);
}
}
private class InnsetF
{
private float top, bottom, left, right;
public InnsetF (float left, float top, float right, float bottom)
{
this.top = top;
this.left = left;
this.bottom = bottom;
this.right = right;
}
public float Top
{
get { return top; }
set { top = value; }
}
public float Bottom
{
get { return bottom; }
set { bottom = value; }
}
public float Right
{
get { return right; }
set { right = value; }
}
public float Left
{
get { return left; }
set { left = value; }
}
}
}
}
So you want the reverse of what Spotify does when it is offline (the string message you're referring to appears above the UINavigationController).
I don't think the approach you're taking is going to work - as far as I know, the NavigationBar can only be 44 pixels high. Could you take a similar approach to Spotify and move it above the NavigationBar? This way you could leave the NavigationController etc as is and simply make it's view smaller, then add the string to the window object - that way it will persist as you navigate through your application.