I'm using a UITabbarViewController in a relatively simple way. My issue only appears on iPad devices of iOS11 version. It's not visible on iOS10 or iPhone.
If you look at the screenshot, you can see that the background color of the tab is not aligned. Actually, it is aligned, it's the tabbar itself that is not taking the full width. So the background color is overlapping towards the central button because it's not using the space on the far left and far right.
I'm assuming that the tabbar is broken (and not my background colors, which are drawn manually) because the edges of the outsides tabs are not clickable, and yet the item positioning is set to be filling the width of the screen :
TabBar.ItemPositioning = UITabBarItemPositioning.Fill;
The items sizes are wrong if you consider the tabbar fullscreen, but they are if you consider the "reduced" version. So i'm pretty sure it's all good there, as long as the tabbar decides to take the full width of the screen, the buttons and background color will then have the correct measurements.
I've tried using View.LayoutIfNeeded() and SetNeedsLayout() to force a redraw, but to no avail.
I'm not sure why it's even behaving like so, and since it's the default behaviour of the OS and I haven't done anything particular, I'm not certain of what can even be tried.
Here's some relevant code :
MainTabbarController tabController = (MainTabbarController)Window.RootViewController;
public override void ViewDidLayoutSubviews()
{
base.ViewDidLayoutSubviews();
ConfigureTabbar();
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
UIViewController[] tabs = //Create the VCs in the most basic way
SetViewControllers(tabs, false);
}
protected virtual void ConfigureTabbar()
{
TabBar.Translucent = false;
TabBar.ItemPositioning = UITabBarItemPositioning.Fill;
TabBar.ItemSpacing = 0;
//View.LayoutIfNeeded();
float tabbarItemWidth = (float)Math.Ceiling(View.Bounds.Width / TabBar.Items.Length) + 1; //+ 1 to avoid the right pixel that was not filled on the right tab. Strange behaviour...
TabBar.ItemWidth = tabbarItemWidth;
//var version = NSProcessInfo.ProcessInfo.OperatingSystemVersion;
NSOperatingSystemVersion ios11 = new NSOperatingSystemVersion(11, 0, 0);
if (NSProcessInfo.ProcessInfo.IsOperatingSystemAtLeastVersion(ios11))
{
if (UIDevice.CurrentDevice.UserInterfaceIdiom == UIUserInterfaceIdiom.Pad)
{
TabBar.SelectionIndicatorImage = _viewModel.Styles.Colors.ActiveTabColor.ToNative().ToImage(new CGRect(0, -View.SafeAreaInsets.Bottom, tabbarItemWidth, TabBar.Frame.Height));
}
else
{
TabBar.SelectionIndicatorImage = _viewModel.Styles.Colors.ActiveTabColor.ToNative().ToImage(new CGRect(0, -View.SafeAreaInsets.Bottom, tabbarItemWidth, TabBar.Frame.Height));
}
}
else
{
TabBar.SelectionIndicatorImage = _viewModel.Styles.Colors.ActiveTabColor.ToNative().ToImage(new CGSize(tabbarItemWidth, TabBar.Frame.Height));
}
UITextAttributes attrs = new UITextAttributes();
attrs.Font = _viewModel.Styles.Fonts.ExtraSmall.ToNative();
attrs.TextColor = _viewModel.Styles.Colors.ActionText.ToNative();
UITabBarItem.Appearance.SetTitleTextAttributes(attrs, UIControlState.Normal);
for (int i = 0; i < TabBar.Items.Length; i++)
{
UITabBarItem item = TabBar.Items[i];
item.Title = _viewModel.Titles[i];
item.TitlePositionAdjustment = new UIOffset(0, -4);
item.ImageInsets = new UIEdgeInsets(-2, 0, 2, 0);
}
//View.LayoutIfNeeded();
}
Related
How do I render a UIButton in Xamarin.iOS? See the current Code for the full list.
This is the code I'm using to create and add the button to the Xamarin.Forms.Platform.iOS.CellTableViewCell cell. I cannot get the button to display anything.
With the use of a Foundation.NSMutableAttributedString, it shows a cut-off section of text in the top left corner, regardless of anything I try (alignments, insets, bounds, various constraints, etc). I'm currently trying things from Xamarin.Forms.Platform.iOS.Renderers.ButtonRenderer, but still can't get anything to display at all, no text, no button, or its outline.
If you could fork the repo and fix it or post the solution here, I would be very grateful.
protected override void SetUpContentView()
{
var insets = new UIEdgeInsets(SVConstants.Cell.PADDING.Top.ToNFloat(), SVConstants.Cell.PADDING.Left.ToNFloat(), SVConstants.Cell.PADDING.Bottom.ToNFloat(), SVConstants.Cell.PADDING.Right.ToNFloat());
_Button = new UIButton(UIButtonType.RoundedRect)
{
AutoresizingMask = UIViewAutoresizing.All,
HorizontalAlignment = UIControlContentHorizontalAlignment.Center,
VerticalAlignment = UIControlContentVerticalAlignment.Center,
ContentEdgeInsets = insets,
// TitleEdgeInsets = insets
};
DefaultFontSize = _Button.TitleLabel.ContentScaleFactor;
DefaultTextColor = _Button.TitleLabel.TextColor;
_Recognizer = new UILongPressGestureRecognizer(RunLong);
_Button.TouchUpInside += OnClick; // https://stackoverflow.com/a/51593238/9530917
_Button.AddGestureRecognizer(_Recognizer); // https://stackoverflow.com/a/6179591/9530917
ContentView.AddSubview(_Button);
_Button.CenterXAnchor.ConstraintEqualTo(ContentView.CenterXAnchor).Active = true;
_Button.CenterYAnchor.ConstraintEqualTo(ContentView.CenterYAnchor).Active = true;
_Button.WidthAnchor.ConstraintEqualTo(ContentView.WidthAnchor).Active = true;
_Button.HeightAnchor.ConstraintEqualTo(ContentView.HeightAnchor).Active = true;
UpdateConstraintsIfNeeded();
LayoutIfNeeded();
}
Found out that you can't subclass it. Any button added to the view must be native (UIButton) or custom rendered, such as Xamarin.Forms.Platform.iOS.ButtonRenderer; It doesn't show up otherwise.
My application supports the iOS system darkmode change. However it got a little bit tricky with the status bar color but in the end i managed to change it aswell.
My problem is, when you are on an iPad in Portrait mode and you switch the Theme, and then tilt the iPad to Landscape mode, the extension of the status bar keeps the old color (See screenshot below)
I don't know if this is just a nasty bug or if i'm doing something wrong. In case it's a bug i would love to have a workaround for this.
Here's how i'm changing the status bar color in a CustomRenderer (in this example to Light Mode)
if (UIDevice.CurrentDevice.CheckSystemVersion(13, 0))
{
UIView statusBar = new UIView(UIApplication.SharedApplication.KeyWindow.WindowScene.StatusBarManager.StatusBarFrame);
statusBar.BackgroundColor = Color.FromHex("#FFFFFF").ToUIColor();
UIApplication.SharedApplication.KeyWindow.AddSubview(statusBar);
}
this.NavigationController.NavigationBar.BarTintColor = Color.FromHex("#FFFFFF").ToUIColor();
This gets called in the TraitCollectionDidChange function.
This is because you used Frame to add a custom status bar. When it runs into the landscape its width remains the portrait's value. Try to change it to autolayout like:
if (UIDevice.CurrentDevice.CheckSystemVersion(13, 0))
{
UIView statusBar = new UIView();
statusBar.TranslatesAutoresizingMaskIntoConstraints = false;
statusBar.BackgroundColor = UIColor.White;
UIApplication.SharedApplication.KeyWindow.AddSubview(statusBar);
statusBar.LeadingAnchor.ConstraintEqualTo(UIApplication.SharedApplication.KeyWindow.LeadingAnchor).Active = true;
statusBar.TopAnchor.ConstraintEqualTo(UIApplication.SharedApplication.KeyWindow.TopAnchor).Active = true;
statusBar.TrailingAnchor.ConstraintEqualTo(UIApplication.SharedApplication.KeyWindow.TrailingAnchor).Active = true;
statusBar.HeightAnchor.ConstraintEqualTo(UIApplication.SharedApplication.KeyWindow.WindowScene.StatusBarManager.StatusBarFrame.Height).Active = true;
}
Update
If you want to change the color back to the original value, try the code here:
public override void TraitCollectionDidChange(UITraitCollection previousTraitCollection)
{
base.TraitCollectionDidChange(previousTraitCollection);
if (UIDevice.CurrentDevice.CheckSystemVersion(13, 0))
{
var window = UIApplication.SharedApplication.KeyWindow;
UIView statusBar;
if (window.ViewWithTag(4) != null)
{
statusBar = window.ViewWithTag(4);
}
else
{
statusBar = new UIView();
statusBar.TranslatesAutoresizingMaskIntoConstraints = false;
statusBar.Tag = 4;
UIApplication.SharedApplication.KeyWindow.AddSubview(statusBar);
statusBar.LeadingAnchor.ConstraintEqualTo(UIApplication.SharedApplication.KeyWindow.LeadingAnchor).Active = true;
statusBar.TopAnchor.ConstraintEqualTo(UIApplication.SharedApplication.KeyWindow.TopAnchor).Active = true;
statusBar.TrailingAnchor.ConstraintEqualTo(UIApplication.SharedApplication.KeyWindow.TrailingAnchor).Active = true;
statusBar.HeightAnchor.ConstraintEqualTo(UIApplication.SharedApplication.KeyWindow.WindowScene.StatusBarManager.StatusBarFrame.Height).Active = true;
}
if (previousTraitCollection.UserInterfaceStyle == UIUserInterfaceStyle.Light)
{
statusBar.BackgroundColor = UIColor.White;
}
else
{
statusBar.BackgroundColor = UIColor.Clear;
}
}
}
If this is not what you want, could you please add more descriptions about your issue?
BTW, if you want to add some transition, try this:
UIView.Animate(0.3, () =>
{
statusBar.BackgroundColor = UIColor.White;
});
The title is pretty self explanatory, on iOS 10.3 using a UIBarButtonItem with a custom view (in this case UIStackView) assigned to a LeftBarButtonItem of a NavigationBar is not visible on iOS 11. I haven't figure out why it is not showed but when I type something with the keyboard my logic of the TextChanged event works! So the UISearchView is there but it is not visible:
Here is some code (It is coded with C# but it is using Objective C methods.):
var width = NavigationController.NavigationBar.Frame.Width;
var height = NavigationController.NavigationBar.Frame.Height;
_searchBarContainer = new UIStackView(new CGRect(0, 0, width * 0.75, height))
{
Alignment = UIStackViewAlignment.Center,
Axis = UILayoutConstraintAxis.Horizontal,
Spacing = 3
};
_uiSearchBar = new UISearchBar
{
BackgroundColor = UIColor.Clear,
BarTintColor = UIColor.Clear,
BackgroundImage = new UIImage(),
Placeholder = Strings.Search
};
_uiSearchBar.SizeToFit();
if (_iOS11)
{
_uiSearchBar.HeightAnchor.ConstraintEqualTo(44).Active = true;
}
_searchbarButtonItem = new UIBarButtonItem(_searchBarContainer);
NavigationItem.SetLeftBarButtonItem(_searchbarButtonItem, true);
ParentViewController.NavigationItem.LeftBarButtonItem = NavigationItem.LeftBarButtonItem;
Using the same code on iOS 10 this works.
Please try out setting up constraints to size properly your _searchBarContainer before setting it as the left bar button item. From iOS11 navigations bars use auto layout. Make sure you only add the constraints if iOS 11 is present, I was having problems in iOS 9 navigation bars otherwise.
Also checkout this thread in the Dev forum where it's explained how the bar items are wrapped inside stack views, maybe also helps with your particular issue.
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.
When I create a new UIDatePicker with its Mode set to a CountDownTimer, it renders poorly with a black background. Anyone have any insight?
Normal Picker looks like this:
CODE: Note the UIButton is a full screen button behind the picker to dismiss the view
intervalPicker = new UIDatePicker(new RectangleF(0, this.tvc.View.Bounds.Height - 135, this.tvc.View.Bounds.Width, 200));
intervalPicker.Mode = UIDatePickerMode.CountDownTimer;
intervalPicker.CountDownDuration = DeviceSession.CurrentBehavioralEvent.Duration*60;
intervalPicker.ValueChanged += new EventHandler(intervalPicker_EditingChanged);
UIButton b = UIButton.FromType(UIButtonType.Custom);
b.Opaque = false;
b.BackgroundColor = UIColor.Clear;
b.Frame = new RectangleF(0, 0, this.tvc.View.Bounds.Width, this.tvc.View.Bounds.Height);
b.TouchUpInside += (o, s) => {
intervalPicker.RemoveFromSuperview();
b.RemoveFromSuperview();
};
this.tvc.NavigationController.View.AddSubview(b);
this.tvc.NavigationController.View.AddSubview(intervalPicker);
The UIDatePicker in CountDownTimer mode displays this way when you set a frame height of less than 216. The other modes don't have this problem.
Your example is setting the height to 200.
Change the height to 216.