How can i disable or hide the Indicator in the UIActivityIndicatorView?
public class ActivityView : UIActivityIndicatorView {
public ActivityView (CGRect frame) : base (frame){
}
public bool IsLoading {
get {
return !this.Hidden;
}
set {
if (value) {
this.Hidden = false;
this.StartAnimating ();
} else {
this.StopAnimating ();
}
}
}
}
Just add this:
this.TintColor = UIColor.Clear;
this.Color = UIColor.Clear;
in this part:
if (value) {
...
this.TintColor = UIColor.Clear;
this.Color = UIColor.Clear;
}
Related
I am creating a cross platform app on xamarin.forms. I needed a custom renderer with gradient background and i've created it and it works well on both android and ios.
However, when i want to change the colors of the gradient background, it does not work on iOS.
Test.xaml.cs
namespace KiaiDay
{
public class TesteViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private Color _startColor = Color.Green;
public Color SStartColor
{
get => _startColor;
set { _startColor = value; OnPropertyChanged(nameof(SStartColor)); }
}
private Color _endColor = Color.Blue;
public Color EEndColor
{
get => _endColor;
set { _endColor = value; OnPropertyChanged(nameof(EEndColor)); }
}
public ICommand Select
{
get => new Command(() =>
{
SStartColor = Color.Red;
EEndColor = Color.Brown;
});
}
#region INotifyPropertyChanged Implementation
void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
if (PropertyChanged == null)
return;
PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class teste : ContentPage
{
public teste()
{
BindingContext = new TesteViewModel();
InitializeComponent();
}
}
}
Test.xaml
<ContentPage.Content>
<StackLayout HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">
<local:ShadowFrame StartColor="{Binding SStartColor}" EndColor="{Binding EEndColor}" HorizontalOptions="Center" VerticalOptions="Center">
<Label Text="Teste"/>
<local:ShadowFrame.GestureRecognizers>
<TapGestureRecognizer NumberOfTapsRequired="1" Command="{Binding Select}"/>
</local:ShadowFrame.GestureRecognizers>
</local:ShadowFrame>
</StackLayout>
</ContentPage.Content>
Custom Renderer in PCL
public class ShadowFrame : Frame
{
public static BindableProperty ElevationProperty = BindableProperty.Create(nameof(Elevation), typeof(float), typeof(ShadowFrame), default(float));
public static readonly BindableProperty StartColorProperty = BindableProperty.Create(nameof(StartColor), typeof(Color), typeof(ShadowFrame), default(Color));
public static readonly BindableProperty EndColorProperty = BindableProperty.Create(nameof(EndColor), typeof(Color), typeof(ShadowFrame), default(Color));
public float Elevation
{
get { return (float)GetValue(ElevationProperty); }
set { SetValue(ElevationProperty, value); }
}
public Color StartColor
{
get { return (Color)GetValue(StartColorProperty); }
set { SetValue(StartColorProperty, value); }
}
public Color EndColor
{
get { return (Color)GetValue(EndColorProperty); }
set { SetValue(EndColorProperty, value); }
}
}
iOS Renderer(i think the problem is here)
[assembly: ExportRenderer(typeof(ShadowFrame), typeof(ShadowFrameRenderer))]
namespace KiaiDay.iOS.Renderers
{
public class ShadowFrameRenderer : FrameRenderer
{
CAGradientLayer gradientLayer;
private Color StartColor { get; set; }
private Color EndColor { get; set; }
CGRect rect;
public static void Initialize()
{
// empty, but used for beating the linker
}
public ShadowFrameRenderer() => gradientLayer = new CAGradientLayer();
public override void Draw(CGRect rect)
{
this.rect = rect;
var stack = (ShadowFrame)this.Element;
StartColor = stack.StartColor;
EndColor = stack.EndColor;
CGColor startColor = this.StartColor.ToCGColor();
CGColor endColor = this.EndColor.ToCGColor();
#region for Vertical Gradient
//var gradientLayer = new CAGradientLayer();
#endregion
#region for Horizontal Gradient
//var gradientLayer = new CAGradientLayer()
//{
// StartPoint = new CGPoint(0, 0.5),
// EndPoint = new CGPoint(1, 0.5)
//};
#endregion
gradientLayer.Frame = rect;
gradientLayer.Colors = new CGColor[] {
startColor,
endColor
};
NativeView.Layer.InsertSublayer(gradientLayer, 0);
base.Draw(rect);
}
protected override void OnElementChanged(ElementChangedEventArgs<Frame> e)
{
base.OnElementChanged(e);
var stack = (ShadowFrame)e.NewElement;
if (e.OldElement != null || Element == null)
{
return;
}
try
{
this.StartColor = stack.StartColor;
this.EndColor = stack.EndColor;
UpdateShadow();
Draw(rect);
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine("ERROR:", ex.Message);
}
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
var stack = (ShadowFrame) sender;
if (e.PropertyName == ShadowFrame.ElevationProperty.PropertyName)
{
UpdateShadow();
}
if (e.PropertyName == ShadowFrame.StartColorProperty.PropertyName)
{
this.StartColor = stack.StartColor;
}
if (e.PropertyName == ShadowFrame.EndColorProperty.PropertyName)
{
this.EndColor = stack.EndColor;
}
}
private void UpdateShadow()
{
var shadowFrame = (ShadowFrame)Element;
// Update shadow to match better material design standards of elevation
Layer.ShadowRadius = shadowFrame.Elevation;
Layer.ShadowColor = UIColor.Gray.CGColor;
Layer.ShadowOffset = new CGSize(2, 2);
Layer.ShadowOpacity = 0.80f;
Layer.ShadowPath = UIBezierPath.FromRect(Layer.Bounds).CGPath;
Layer.MasksToBounds = false;
}
}
}
I would like to update iOS view immediatly after i change the color through the command.
If you change a property and the view doesn't update the issue has to be in OnElementPropertyChanged.
You need to call UpdateShadow() and Draw().
After digging a lot i think i have found a solution:
iOS Custom Renderer :
public class GradientStackColorRenderer : VisualElementRenderer<Frame>
{
private Color StartColor { get; set; }
private Color EndColor { get; set; }
public override CGRect Frame
{
get
{
return base.Frame;
}
set
{
if (value.Width > 0 && value.Height > 0)
{
foreach (var layer in NativeView?.Layer.Sublayers.Where(layer => layer is CAGradientLayer))
layer.Frame = new CGRect(0, 0, value.Width, value.Height);
}
base.Frame = value;
}
}
protected override void OnElementChanged(ElementChangedEventArgs<StackLayout> e)
{
base.OnElementChanged(e);
if (e.OldElement == null)
{
try
{
var stack = e.NewElement as GradientColorStack;
this.StartColor = stack.StartColor;
this.EndColor = stack.EndColor;
AdicionarGradiente();
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(#"ERROR:", ex.Message);
}
}
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
var stack = this.Element as GradientColorStack;
if(e.PropertyName == GradientColorStack.StartColorProperty.PropertyName)
{
this.StartColor = stack.StartColor;
AdicionarGradiente();
}
if (e.PropertyName == GradientColorStack.EndColorProperty.PropertyName)
{
this.EndColor = stack.EndColor;
AdicionarGradiente();
}
}
public void AdicionarGradiente()
{
var gradient = new CAGradientLayer();
gradient.CornerRadius = NativeView.Layer.CornerRadius = 5;
gradient.Colors = new CGColor[] { StartColor.ToCGColor(), EndColor.ToCGColor() };
var layer = NativeView?.Layer.Sublayers.LastOrDefault();
NativeView?.Layer.InsertSublayerBelow(gradient, layer);
}
public static CGColor ToCGColor(Color color)
{
return new CGColor(CGColorSpace.CreateSrgb(), new nfloat[] { (float)color.R, (float)color.G, (float)color.B, (float)color.A });
}
}
I user custom UITextView and need to hide keyboard on return click. I need to catch 'ShouldChangeTextInRange' what has textview, I don't know why but
method is not called. here is code of for my text view :
public class PlaceholderTextView : UITextView
{
public PlaceholderTextView ()
{
Initialize ();
}
public PlaceholderTextView (CGRect frame)
: base (frame)
{
Initialize ();
}
public PlaceholderTextView (IntPtr handle)
: base (handle)
{
Initialize ();
}
void Initialize ()
{
Text = Placeholder;
ShouldBeginEditing = t => {
if (Text == Placeholder)
Text = string.Empty;
return true;
};
ShouldEndEditing = t => {
if (string.IsNullOrEmpty (Text))
Text = Placeholder;
return true;
};
}
public override bool ShouldChangeTextInRange (UITextRange inRange, string replacementText)
{
if (Text.Equals ("\n")) {
this.EndEditing (true);
return false;
} else {
return true;
}
}
}
In your UITextView subclass, add IUITextViewDelegate and implement ShouldChangeText (selector = textView:shouldChangeTextInRange:replacementText:):
public class MyTextView : UITextView, IUITextViewDelegate
{
string Placeholder;
public MyTextView()
{
Initialize();
}
public MyTextView(Foundation.NSCoder coder) : base(coder)
{
Initialize();
}
public MyTextView(Foundation.NSObjectFlag t) : base(t)
{
Initialize();
}
public MyTextView(IntPtr handle) : base(handle)
{
Initialize();
}
public MyTextView(CoreGraphics.CGRect frame) : base(frame)
{
Initialize();
}
public MyTextView(CoreGraphics.CGRect frame, NSTextContainer textContainer) : base(frame, textContainer)
{
Initialize();
}
void Initialize()
{
Delegate = this;
}
[Export("textViewShouldBeginEditing:")]
public bool ShouldBeginEditing(UITextView textView)
{
if (Text == Placeholder)
Text = string.Empty;
return true;
}
[Export("textViewShouldEndEditing:")]
public bool ShouldEndEditing(UITextView textView)
{
if (string.IsNullOrEmpty(Text))
Text = Placeholder;
return true;
}
[Export("textView:shouldChangeTextInRange:replacementText:")]
public bool ShouldChangeText(UITextView textView, NSRange range, string text)
{
if (text.Contains("\n"))
{
this.EndEditing(true);
return false;
}
return true;
}
}
Note: You can not mix using ObjC/Swift style Delegates and C# anonymous Delegates, otherwise you end up with the error:
Event registration is overwriting existing delegate. Either just use events or your own delegate
I have a Tag class inflated from a nib file:
using Foundation;
using System;
using UIKit;
using ObjCRuntime;
namespace TagTest
{
public partial class Tag : UIView
{
public Tag (IntPtr handle) : base (handle)
{
}
public static Tag Create()
{
var arr = NSBundle.MainBundle.LoadNib("Tag", null, null);
var v = Runtime.GetNSObject<Tag>(arr.ValueAt(0));
return v;
}
public override void AwakeFromNib()
{
}
public UIButton Hashtag
{
get
{
return HashtagBtn;
}
}
public UILabel HashtagCount
{
get
{
return HashtagCountLbl;
}
}
}
}
which is used by the following viewmodel
using System.Collections.Generic;
using MvvmCross.Binding.BindingContext;
using MvvmCross.iOS.Views;
using TagTest.Core.ViewModels;
using UIKit;
using Cirrious.FluentLayouts.Touch;
using System;
using System.Drawing;
namespace TagTest
{
public partial class SearchView : MvxViewController
{
List<Tag> _tags;
public SearchView () : base ("SearchView", null)
{
}
new SearchViewModel ViewModel
{
get
{
return (SearchViewModel)base.ViewModel;
}
set
{
base.ViewModel = value;
}
}
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
DisplayTags();
View.UserInteractionEnabled = false;
View.SubviewsDoNotTranslateAutoresizingMaskIntoConstraints();
View.TranslatesAutoresizingMaskIntoConstraints = false;
EdgesForExtendedLayout = UIRectEdge.None;
ExtendedLayoutIncludesOpaqueBars = false;
AutomaticallyAdjustsScrollViewInsets = false;
View.ClipsToBounds = true;
View.BackgroundColor = UIColor.Red;
CreateBindings ();
}
public override void ViewDidAppear(bool animated)
{
base.ViewDidAppear(animated);
ViewModel.Init();
}
void CreateBindings()
{
var set = this.CreateBindingSet<SearchView, SearchViewModel> ();
set.Bind (this).For(x => x.Title).To (vm => vm.Title);
set.Apply ();
}
public override void ViewDidLayoutSubviews()
{
base.ViewDidLayoutSubviews();
View.LayoutIfNeeded();
}
void DisplayTags()
{
_tags = new List<Tag>();
if (ViewModel.Tags != null)
{
foreach (var item in ViewModel.Tags)
{
_tags.Add(Tag.Create());
}
UIView lastTemplateAdded = View;
for (int i = 0; i < _tags.Count; i++)
{
var tag = _tags[i];
tag.TranslatesAutoresizingMaskIntoConstraints = false;
tag.Hashtag.SetTitle(ViewModel.Tags[i].Tagname, UIControlState.Normal);
tag.HashtagCount.Text = ViewModel.Tags[i].Count.ToString();
tag.Frame = new RectangleF(100f, 300f, 100f, 50f);
tag.Hashtag.Enabled = true;
tag.Hashtag.UserInteractionEnabled = true;
tag.UserInteractionEnabled = true;
tag.Hashtag.TouchUpInside += (sender, e) =>
{
ViewModel.TagSelectedCommand.Execute(tag);
};
View.AddSubview(tag);
if (i == 0)
{
View.AddConstraints(
tag.AtTopOf(View),
tag.AtLeftOf(View),
tag.Height().EqualTo(20)
);
}
else
{
View.AddConstraints(
tag.Below(lastTemplateAdded, 20),
tag.AtLeftOf(View),
tag.Height().EqualTo(20)
);
}
lastTemplateAdded = tag;
}
}
}
public override void DidReceiveMemoryWarning ()
{
base.DidReceiveMemoryWarning ();
// Release any cached data, images, etc that aren't in use.
}
}
}
but the Hashtag button is not clickable, the TouchupInside doesn't appear to be fired. If I add a single button to the view it is clickable. What could be going wrong?
Found the problem. It was a combination of setting View.UserInteractionEnabled = false; and using the fluent constraints. I've now set UserInteractioEnabled to true and removed the fluent constraints. All working now.
Hi I'm having an issue trying to bind MvxTableViewCell accessory Checkmark to a local property. I've tried following an example found at Bind MvxBindableTableViewCell's Accessory to boolean
I'm quite new to IOS and even newer to MvvmCross so I apologize if I've made any silly mistakes
public partial class TaxaListCellView : MvxTableViewCell
{
public static readonly UINib Nib = UINib.FromName ("TaxaListCellView", NSBundle.MainBundle);
public static readonly NSString Key = new NSString ("TaxaListCellView");
public TaxaListCellView (IntPtr handle) : base (handle)
{
Accessory = UITableViewCellAccessory.Checkmark;
SelectionStyle = UITableViewCellSelectionStyle.None;
this.DelayBind (() => {
var set = this.CreateBindingSet<TaxaListCellView, TaxonViewModel>();
set.Bind(lblSelectedTaxon).To(s => s.Name);
//I've been playing around with both ways below, and a few different
//variants without any success
//set.Bind("IsChecked").To(s => s.IsSelected).TwoWay();
//set.Bind(#"'IsChecked':{'Path':'IsSelected'");
set.Apply();
});
}
public bool IsChecked
{
get { return Accessory == UITableViewCellAccessory.Checkmark; }
set { Accessory = value ? UITableViewCellAccessory.Checkmark : UITableViewCellAccessory.None; }
}
public static TaxaListCellView Create ()
{
return (TaxaListCellView)Nib.Instantiate (null, null) [0];
}
public override void SetSelected (bool selected, bool animated)
{
Accessory = selected ? UITableViewCellAccessory.Checkmark : UITableViewCellAccessory.None;
base.SetSelected (selected, animated);
}
}
I'm not sure if there is anything wrong with my MvxTableViewController but here's the code
public class TaxaListView : MvxTableViewController
{
public TaxaListView()
{
Title = "Taxon List";
}
private UISearchBar _searchBar;
public override void ViewDidLoad()
{
base.ViewDidLoad();
_searchBar = new UISearchBar(new RectangleF(0,0,320, 44))
{
AutocorrectionType = UITextAutocorrectionType.Yes,
};
_searchBar.SearchButtonClicked += SearchBar_SearchButtonClicked;
_searchBar.TextChanged += SearchBarOnTextChanged;
var source = new MvxSimpleTableViewSource(TableView, TaxaListCellView.Key, TaxaListCellView.Key);
var set = this.CreateBindingSet<TaxaListView, TaxaListViewModel> ();
set.Bind (source).To (vm => vm.Taxa);
set.Bind (source)
.For (s => s.SelectionChangedCommand)
.To (vm => vm.ItemSelectedCommand);
set.Apply ();
TableView.RowHeight = 50;
TableView.Source = source;
TableView.AllowsSelection = true;
TableView.AllowsSelectionDuringEditing = true;
TableView.TableHeaderView = _searchBar;
TableView.ReloadData();
}
private void SearchBarOnTextChanged(object sender, UISearchBarTextChangedEventArgs uiSearchBarTextChangedEventArgs)
{
if(string.IsNullOrWhiteSpace(_searchBar.Text))
{
((TaxaListViewModel) ViewModel).SearchTaxaByText(string.Empty);
}
}
void SearchBar_SearchButtonClicked(object sender, System.EventArgs e)
{
((TaxaListViewModel)ViewModel).SearchTaxaByText(_searchBar.Text);
}
}
When I Select an item from the list first
When i start searching, Or happens even if i go back into the list of items
As Stuart alluded too, I needed to tell the ViewModel the value had changed.
I removed the SetSelelted method as this was causing problems when the cell was loading
public partial class TaxaListCellView : MvxTableViewCell
{
public static readonly UINib Nib = UINib.FromName ("TaxaListCellView", NSBundle.MainBundle);
public static readonly NSString Key = new NSString ("TaxaListCellView");
private const string BindingText = "Name Name; IsChecked IsSelected";
public TaxaListCellView() : base(BindingText)
{
Accessory = UITableViewCellAccessory.Checkmark;
SelectionStyle = UITableViewCellSelectionStyle.None;
}
public TaxaListCellView (IntPtr handle) : base (BindingText,handle)
{
Accessory = UITableViewCellAccessory.Checkmark;
SelectionStyle = UITableViewCellSelectionStyle.None;
}
public string Name
{
get { return lblSelectedTaxon.Text; }
set { lblSelectedTaxon.Text = value; }
}
public bool IsChecked
{
get { return Accessory == UITableViewCellAccessory.Checkmark; }
set { Accessory = value ? UITableViewCellAccessory.Checkmark : UITableViewCellAccessory.None; }
}
public static TaxaListCellView Create ()
{
return (TaxaListCellView)Nib.Instantiate (null, null) [0];
}
}
In My TaxaListView class
public override void ViewDidLoad()
{
base.ViewDidLoad();
_searchBar = new UISearchBar(new RectangleF(0,0,320, 44))
{
AutocorrectionType = UITextAutocorrectionType.Yes,
};
_searchBar.SearchButtonClicked += SearchBar_SearchButtonClicked;
_searchBar.TextChanged += SearchBarOnTextChanged;
var source = new MvxSimpleTableViewSource(TableView, TaxaListCellView.Key, TaxaListCellView.Key);
var set = this.CreateBindingSet<TaxaListView, TaxaListViewModel> ();
set.Bind (source).To (vm => vm.Taxa);
set.Bind (source)
.For (s => s.SelectionChangedCommand)
.To (vm => vm.ItemSelectedCommand);
set.Apply ();
TableView.RowHeight = 50;
TableView.Source = source;
TableView.AllowsSelection = true;
TableView.AllowsSelectionDuringEditing = true;
TableView.TableHeaderView = _searchBar;
TableView.ReloadData();
}
I Bind the selectedChangedCommand and in my ViewModel class I raise the Property changed event
private MvxCommand<TaxonViewModel> _itemSelectedCommand;
public ICommand ItemSelectedCommand
{
get
{
_itemSelectedCommand = _itemSelectedCommand ?? new MvxCommand<TaxonViewModel>(DoSelectedItem);
return _itemSelectedCommand;
}
}
private void DoSelectedItem(TaxonViewModel item)
{
Taxa.First(r => r.TaxonId == item.TaxonId).IsSelected = true;
RaisePropertyChanged("Taxon");
}
I'm trying to update an imageview (an outlet from Xcode) from another class, but it didn't work.
AppDelegate:
public UIImageView imageviewLoanInputTabs
{
get;
private set;
}
public override bool FinishedLaunching (UIApplication app, NSDictionary options)
{
imageviewLoanInputTabs = new UIImageView ();
return true;
}
The other class:
var imageObjOutraClass = (AppDelegate) UIApplication.SharedApplication.Delegate;
imageObjOutraClass.imageviewLoanInputTabs.Image = (UIImage.FromBundle ("image11.png"));
There's no special trick to manipulating UIImageViews. Try the following code:
using System;
using System.Collections.Generic;
using System.Linq;
using MonoTouch.Foundation;
using MonoTouch.UIKit;
using System.Drawing;
using MonoTouch.CoreGraphics;
namespace SingleFileSolution
{
public class ContentView : UIView
{
public ContentView Companion { get; set; }
public UIImage Image {
get
{
return imageView.Image;
}
set
{
imageView.Image = value;
}
}
private UIImageView imageView;
public ContentView(UIColor fillColor, UIImage initialImage)
{
this.BackgroundColor = fillColor;
imageView = new UIImageView(new RectangleF(10, 60, initialImage.Size.Width, initialImage.Size.Height));
imageView.Image = initialImage;
AddSubview(imageView);
UIButton swapButton = UIButton.FromType(UIButtonType.RoundedRect);
swapButton.SetTitle("Swap Image", UIControlState.Normal);
swapButton.TouchUpInside += (sender, e) => {
if(Companion != null)
{
var tmp = Companion.Image;
Companion.Image = this.Image;
this.Image = tmp;
}
};
swapButton.Frame = new RectangleF(10, 10, 100, 44);
AddSubview(swapButton);
}
}
public class SimpleViewController : UIViewController
{
public SimpleViewController() : base ()
{
}
public override void DidReceiveMemoryWarning()
{
base.DidReceiveMemoryWarning();
}
public override void ViewDidLoad()
{
var view1 = new ContentView(UIColor.Blue, UIImage.FromFile("image1.jpg"));
var view2 = new ContentView(UIColor.Red, UIImage.FromFile("image2.jpg"));
view1.Frame = new RectangleF(0, 0, UIScreen.MainScreen.Bounds.Width, UIScreen.MainScreen.Bounds.Height / 2);
view2.Frame = new RectangleF(0, UIScreen.MainScreen.Bounds.Height / 2, UIScreen.MainScreen.Bounds.Width, UIScreen.MainScreen.Bounds.Height / 2);
view1.Companion = view2;
view2.Companion = view1;
var view = new UIView(new RectangleF(new PointF(0, 0), UIScreen.MainScreen.Bounds.Size));
view.AddSubview(view1);
view.AddSubview(view2);
this.View = view;
}
}
[Register ("AppDelegate")]
public class AppDelegate : UIApplicationDelegate
{
UIWindow window;
SimpleViewController svController;
UINavigationController navController;
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
window = new UIWindow(UIScreen.MainScreen.Bounds);
svController = new SimpleViewController();
window.RootViewController = svController;
window.MakeKeyAndVisible();
return true;
}
}
public class Application
{
static void Main(string[] args)
{
UIApplication.Main(args, null, "AppDelegate");
}
}
}