-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Title View's content horizontal aligment #4848
Comments
I think it's better to change the type from [Enhancement] to issue because it's more issue than the enhancement |
Pretty much. At the moment if you have any other items in the nav bar it makes the appearance undesirable and not worth using at all. |
That's a serious issue to us, we're currently waiting to be fixed. |
@PureWeen Hi! Thank you! |
This continues to be an issue in Shell and one that has no reasonable workaround that I'm aware of. Negative margin hacks are prone to miscalculation. Bumping up the impact. |
Hi, |
I recently butted up against this very issue in a Xamarin iOS project and there's no way to solve it using the iOS-supplied UI elements. If you use |
I'm also looking for a solution for this. It's been marked as a duplicate but the duplicate has been closed and references this issue. Is there a solution for this being considered? |
@samhouts Hi, any plan to fix this? As far as I know, many people are paying attention to this problem. |
Sadly the issue remains even with the introduction of shell |
Sadly it doesn't look like it's a priority. |
This blows. Makes our apps look bad. |
This is quite annoying. Does anyone have a workaround? |
@julioas09 I did once make it but forgot how I did. but I was referring these two resources and made it. so I think you can also refer to them and do so. |
Workaround: Implement a title view that has the back button in it as well as the image, then set the navigation item's buttons to null. This should make the title view fill the whole width of the navigation bar. |
Really need this..... zZz |
@programmation Do you have an example for this? |
@jaspervanmegroot
But it is not perfect though, still the left margin is slightly bigger than the right one. |
Alternative workaround: create a dummy, blank, do-nothing button for the opposite side of the navigation bar. |
Sorry for the delay replying to you! I also posted another workaround that has worked for me in the past (however I don’t use Shell so unsure if it will help here): create a dummy button for the right hand side of the navigation bar. You can use text color == background color to make it invisible, and size it by making it have the same text as the left-hand side button.
… On 24 Mar 2020, at 20:43, jaspervanmegroot ***@***.***> wrote:
@programmation <https://github.com/programmation> Do you have an example for this?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub <#4848 (comment)>, or unsubscribe <https://github.com/notifications/unsubscribe-auth/ACNA4OOTRYXWHCX4GKUPEHDRJB6CLANCNFSM4GL6FIBA>.
|
@programmation Thanks! Basically it is working, but it is a bit awkward because if you put toolbar items, then the |
@eli191 I agree it's really not ideal, but that was the best workaround I had while still using the XF-provided |
@programmation Do you have an example project on github? |
Still facing this issue in August 2020. We soon will hit 2 years for this bug. Is there a plan to fix it? |
We now how excellent features like drag & drop and swipe view but i'm still struggling to centre the title. |
Is there any possibility for this to be fixed any soon ? maybe in XF 5 |
Yep, still struggling with this in 2021 :( |
Used this dirty workaround to solve it for now:
|
Unfortunately this does not seem to be a priority event when it was reported in 2018 but still in 2022. |
This is what we use as a workaround (is it a workaround?). The relevant stuff is in the method ApplyToolbarAdjustments. iOS: EDIT (2022-01-28): I had to adjust the computation for iOS >= 16. class CustomNavigationRenderer : NavigationRenderer
{
private readonly Info _info = new Info();
protected override void OnElementChanged(VisualElementChangedEventArgs e)
{
base.OnElementChanged(e);
if (e.OldElement is NavigationPage oldNavigationPage)
{
oldNavigationPage.PropertyChanged -= OnNavigationPagePropertyChanged;
}
if (e.NewElement is NavigationPage navigationPage)
{
SetInfo(navigationPage);
navigationPage.PropertyChanged += OnNavigationPagePropertyChanged;
}
else
{
SetInfo(null);
}
}
private void OnNavigationPagePropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(NavigationPage.CurrentPage))
{
SetInfo(sender as NavigationPage);
}
}
public override void ViewDidLayoutSubviews()
{
base.ViewDidLayoutSubviews();
ApplyToolbarAdjustments();
}
private void ApplyToolbarAdjustments()
{
if (_info.TitleView != null && NavigationBar != null)
{
UIView containerView = FindContainerViewInSubviews(NavigationBar);
if (containerView != null)
{
UIView uiBarNavigationContentView = containerView.Superview;
// Set negative horizontal padding of the PageTitleView (which is a PyjamaGrid)
// in order to compensate for the built-in padding of the navigation bar.
// Note that we can't use PageTitleView.Margin here because changes to the margin
// are applied when the page is already visible (I don't know why),
// which results in a jumping of the title visuals.
double horizontalOffset;
if (DeviceInfo.Version.Major < 16)
{
// Example (Simulator: iOS 15, iPhone 13):
// uiBarNavigationContentView (superview):
// x:0 y:0 w:390 h:44
// containerView:
// x:50 y:0 w:331 h:44
horizontalOffset = containerView.Frame.X;
}
else
{
// Example (Simulator: iOS 16.0, iPhone 14):
// uiBarNavigationContentView (superview):
// x:50 y:0 w:323 h:44
// containerView:
// x:0 y:0 w:323 h:44
horizontalOffset = uiBarNavigationContentView.Frame.X;
}
var mainDisplayInfo = DeviceDisplay.MainDisplayInfo;
var screenWidth = mainDisplayInfo.Width / mainDisplayInfo.Density;
var padding = new Thickness(
-horizontalOffset,
0,
-(screenWidth - containerView.Frame.Width - horizontalOffset),
0);
_info.TitleView.Padding = padding;
}
}
}
/// <summary>
/// Finds the Container instance anywhere in the descendants of the UINavigationBar.
/// Xamarin uses the Container as a container for e.g. the TitleView.
/// </summary>
private UIView FindContainerViewInSubviews(UIView view)
{
foreach (var subView in view.Subviews)
{
// The Container is a private class of NavigationRenderer.
if (subView.GetType().FullName == "Xamarin.Forms.Platform.iOS.NavigationRenderer+Container")
{
return subView;
}
else
{
var descendantView = FindContainerViewInSubviews(subView);
if (descendantView != null)
{
return descendantView;
}
}
}
return null;
}
private void SetInfo(NavigationPage navigationPage)
{
_info.NavigationPage = navigationPage;
_info.CurrentContentPage = navigationPage?.CurrentPage as AppContentPage;
_info.TitleView = navigationPage?.CurrentPage?.GetValue(NavigationPage.TitleViewProperty) as PageTitleView;
}
private sealed class Info
{
public NavigationPage NavigationPage { get; set; }
public PageTitleView TitleView { get; set; }
public AppContentPage CurrentContentPage { get; set; }
}
} Android class CustomNavigationPageRenderer : NavigationPageRenderer
{
private readonly Info _info = new Info();
public CustomNavigationPageRenderer(Context context)
: base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<NavigationPage> e)
{
base.OnElementChanged(e);
if (e.OldElement is NavigationPage oldNavigationPage)
{
oldNavigationPage.PropertyChanged -= OnNavigationPagePropertyChanged;
}
if (e.NewElement is NavigationPage navigationPage)
{
// NOTE: @_Info.Toolbar is set in OnViewAdded which is called before OnElementChanged.
SetInfo(navigationPage);
navigationPage.PropertyChanged += OnNavigationPagePropertyChanged;
}
else
{
SetInfo(null);
}
}
private void OnNavigationPagePropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(NavigationPage.CurrentPage))
{
SetInfo(sender as NavigationPage);
}
}
protected override void OnLayout(bool changed, int left, int top, int right, int bottom)
{
base.OnLayout(changed, left, top, right, bottom);
// Since OnLayout is called many times without the NaviationPage itself being
// changed in position/size: apply adjustments only if IsToolbarAdjustmentPending
// (which is set when a new CurrentPage arrives).
if (changed || _info.IsToolbarAdjustmentPending)
{
_info.IsToolbarAdjustmentPending = false;
ApplyToolbarAdjustments();
}
}
private void ApplyToolbarAdjustments()
{
if (_info.Toolbar != null)
{
_info.Toolbar.SetPadding(0, 0, 0, 0);
_info.Toolbar.SetTitleMargin(0, 0, 0, 0);
if (_info.TitleView != null)
{
// Apply negative padding-left on the title view (which is a PyjamaGrid)
// in order to compensate for the navigation inset (e.g. the back/hamburger icon).
// We can't use the Margin because it's a PyjamaGrid.
_info.TitleView.Padding = new Thickness(
-(_info.Toolbar.ContentInsetStartWithNavigation / DeviceDisplay.MainDisplayInfo.Density),
0, 0, 0);
}
}
}
public override void OnViewAdded(Android.Views.View child)
{
base.OnViewAdded(child);
// NOTE: OnViewAdded is called before OnElementChanged.
// We can't use "Context.GetActivity().FindViewById(Resource.Id.toolbar) as AndroidX.AppCompat.Widget.Toolbar"
// because the NavigationPageRenderer uses an own Toolbar instance.
// Plus that Toolbar is not exposed via a public member,
// thus we have to fish for it here.
if (child is AndroidX.AppCompat.Widget.Toolbar toolbar)
{
_info.Toolbar = toolbar;
}
}
private void SetInfo(NavigationPage navigationPage)
{
_info.NavigationPage = navigationPage;
var currentContentPage = navigationPage?.CurrentPage as AppContentPage;
// Since OnLayout is called many times without the NaviationPage itself being
// changed in position/size: apply adjustments only if IsToolbarAdjustmentPending
// (which is set when a new CurrentPage arrives).
_info.IsToolbarAdjustmentPending = _info.CurrentContentPage != currentContentPage;
_info.CurrentContentPage = currentContentPage;
_info.TitleView = navigationPage?.CurrentPage?.GetValue(NavigationPage.TitleViewProperty) as PageTitleView;
}
private sealed class Info
{
public NavigationPage NavigationPage { get; set; }
public AndroidX.AppCompat.Widget.Toolbar Toolbar { get; set; }
public PageTitleView TitleView { get; set; }
public AppContentPage CurrentContentPage { get; set; }
public bool IsToolbarAdjustmentPending { get; set; }
}
} |
Hi guys, check this out and ping me with code examples if something is still wrong. This is XF project adopted to use with VS2022 for Windows and the latest VS2022 for Mac. You need to run the .Xamarin.Forms.vs2022.iOS.slnf file and deploy the titleview.iOS project. Here is all the changes I've made bondarenkod/repro-xf-titleimage-not-centered@66b04fb You can build nuget using this sources https://github.com/bondarenkod/repro-xf-titleimage-not-centered @xamiell, @beeradmoore, @ChrisTTian667, @devlanfear, @developer9969, @programmation, @rs-mobitech, @VirtualNomad00 , @francis2, @julioas09 , @BradKwon , @drjaydenm , @jaspervanmegroot, @eli191, @MaxFmi , @Hackavist, @julioas09, @kasimier-vireq |
Description
Unable to center horizontally content in the TitleView.
I'm happy to see this feature in XF but I want to offer a few ideas based on this issue how to make this feature more useful.
We can't center the content of custom view horizontally relatively the device screen, it depends on if there is Back button or not, Right item(s) or not, etc.
Steps to Reproduce
Expected Behavior
TitleView's Content should be properly centered.
As we can see the logical horizontal center point of the TitleView's content never will be centered by phone's screen horizontal center point. So, we can't place there any image or dynamic content to create something like that (random image from the Internet):
Actual Behavior
TitleView's Content centered in a wrong way. We can't control that.
Basic Information
Version with issue: >3.1
Last known good version: <=3.1
IDE: VS2017
Platform Target Frameworks:
Nuget Packages:
Xamarin Forms 3.4.0
Affected Devices:
All iOS
Screenshots
Reproduction Link
I made a short example, you can follow this link to see them in code, based on the XF's Xamarin.Forms.ControlGallery example in this branch - just clone and run the iOS app, then select Title View then BDF: TitleView Centered, combine it with the Toggle Toolbar Item
I created a few theoretical examples trying to offer a possible solution on how to solve it. In general, we need to fix the size and position of the TitleView's container to allow center its content.
Default Mode -
The behavior of the View Container the same as now.
Ghost Mode - (if it possible to implement this)
The View Container should use all the navigation bar space. We can overflow some controls by its content, but it's ok for some situations.
Unified Mode
The View Container size should take all the free space regarding the navigation bar items and pin to the bar's center.
The text was updated successfully, but these errors were encountered: