Removing Tabbar from tabbedpage leaves blank space. How to remove it? - xamarin.forms

I want to remove Tabbar from TabbedPage. I got it working but it leaves blank space or page height is not updated after hiding Tabbar.
Note that when we swipe through the pages, the blank goes and never comes back. This issue appears only for the first time.
I have tried from this link. But it doesn't work.
Also tried following
private void Element_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
try
{
TabBar.Hidden = true;
//TabBar.Bounds = new CoreGraphics.CGRect(View.Subviews[0].Frame.X, View.Subviews[0].Frame.Y,
// View.Subviews[0].Frame.Width, 0);
if (TabBar.Hidden)
{
// page
View.Subviews[0].Frame = new CoreGraphics.CGRect(0, 0, View.Subviews[1].Frame.Width, NativeView.Frame.Height);
// Tabbar
View.Subviews[1].Frame = new CoreGraphics.CGRect(View.Subviews[0].Frame.X, View.Subviews[0].Frame.Y,
View.Subviews[0].Frame.Width, 0);
}
else
{
View.Subviews[1].Frame = new CoreGraphics.CGRect(View.Subviews[1].Frame.X, View.Subviews[1].Frame.Y,
View.Subviews[1].Frame.Width, 49);
View.Subviews[0].Frame = new CoreGraphics.CGRect(View.Subviews[0].Frame.X, View.Subviews[0].Frame.Y,
View.Subviews[0].Frame.Width, View.Subviews[0].Frame.Height - 49);
}
//if (TabBar.Hidden)
// View.Subviews[1].Frame = new CoreGraphics.CGRect(View.Subviews[1].Frame.X, View.Subviews[1].Frame.Y, View.Subviews[1].Frame.Width, 0);
//else
// View.Subviews[1].Frame = new CoreGraphics.CGRect(View.Subviews[1].Frame.X, View.Subviews[1].Frame.Y, View.Subviews[1].Frame.Width, 49);
}
catch (Exception ex)
{
//TraceLog("Element_PropertyChanged" + ex.Message);
}
}
EDIT
I open tabbed page on list view item clicked. I allow to add multiple tabs dynamically. Also I have created custom tabbar using ContentView that I update when pages are added or removed from TabbedPage.
The sequence is :
- User opens first tab.
- Click on home icon given on tabbed page.
- open the second page by click on another list item
- swipe through the page and the page height will be normal.
Here is the code on ListView_ItemTapped (Not posted exactly how is it actually but you can get idea :) )
MultiTab ObjMultiTab = new MultiTab(); // Initialize tabbed page
// Get data from server
ObjMultiTab.Data = ObjData;
int Id = Convert.ToInt32(ObjData.id);
if (ActiveList.ContainsKey(Id)) // Dictionary that contains info about index and pageid that are already open
{
TabId = ActiveList[ObjData.id];
CurrentPage = Children[TabId]; // If user taps on already opend page
}
else
{
Count += 1; ActiveList.Add(Id, Count);
Children.Add(new SecondTabbedPage(TableData)); // Or add new child
CurrentPage = Children[Count];
}
await Application.Current.MainPage.Navigation.PushModalAsync(ObjMultiTab);
Is there any way to remove blank space for the first time also ?

Adding following function to the renderer removed blank space from TabbedPage.
public override void ViewDidLayoutSubviews()
{
base.ViewDidLayoutSubviews();
TabBar.Hidden = true;
var page = View.Subviews[0];
var tabbar = View.Subviews[1];
tabbar.Bounds = CGRect.Empty;
page.Bounds = UIScreen.MainScreen.Bounds;
}

There is a solution that doesn't require any renders and works on both Android and iOS.
Wrap the TabbedPage in a NavigationPage so the structure of your app becomes
NavigationPage (root)
TappedPage
NavigationPage
ContentPage (with tabbar)
ContentPage (without tabbar)
On the TabbedPage you have to hide the navigationbar of the 'root' NavigationPage, otherwise you have 2 navbars.
<TabbedPage
...
HasNavigationBar="False">
If you push a page using the 'root' NavigationPage, the tabbar is hidden and there is no blank space at the bottom.
--- Edit ---
See my example at:
https://github.com/Jfcobuss/HideTabbarExample/tree/master/HideTabbarExample
Downside of this solution is
It is bit of an hacky workaround
The title next to back-button is the title of the TabbedPage, not the current tab
The animation to the next page is not as fluent as default

Related

How to fix Menu for Nevigation pages in Master Detail page for all platform(android and uwp)

I have designed master detail page for my application.
Here I past screentshots of my application.
Homepage overview
I use data grid view to show my data.
Menu
but, I don't want to hide my Menu.I fix that in my application home screen for uwp app only.
So after fix that I want to show my data in datagridview for rest of the screen.
I want to unhide Menu.
Is that posiible using master detail page design.
How can I do it, Please any suggestion or code example.
advance thanks.
Customized screen what I want:-
CustomScreen
You can create a MasterDetailPageRenderer in UWP solution as follows:
[assembly: ExportRenderer(typeof(AppMasterDetailDemo.Views.MainPage), typeof(CustomMasterDetailRenderer))]
namespace AppMasterDetailDemo.UWP
{
public class CustomMasterDetailRenderer: MasterDetailPageRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<MasterDetailPage> e)
{
base.OnElementChanged(e);
if (Control != null)
{
Control.CollapsedPaneWidth = 0;
Control.CollapseStyle = Xamarin.Forms.PlatformConfiguration.WindowsSpecific.CollapseStyle.Partial;
Control.MasterToolbarVisibility = Windows.UI.Xaml.Visibility.Collapsed;
Control.DetailTitleVisibility = Windows.UI.Xaml.Visibility.Collapsed;
Control.MasterTitleVisibility = Windows.UI.Xaml.Visibility.Collapsed;
Control.ContentTogglePaneButtonVisibility =
Windows.UI.Xaml.Visibility.Collapsed;
}
}
}
}
Then in Xamarin Forms, set as follows can hide the Menu button.
NavigationPage.SetHasBackButton(this, false);
NavigationPage.SetHasNavigationBar(this, false);
Or modify the false to true, can show again.
The effect:

Interaction with parent control triggers RippleDrawable in Xamarin.Forns custom renderer

I have implemented a custom clickable label class in Xamarin.Forms along with a custom renderer, that adds a RippleDrawable as the controls Foreground. I am creating the RippleDrawable with the following code:
public static Drawable CreateRippleDrawable(Context context)
{
var typedValue = new TypedValue();
context.Theme.ResolveAttribute(Resource.Attribute.SelectableItemBackground, typedValue, true);
var rippleDrawable = context.Resources.GetDrawable(typedValue.ResourceId, context.Theme);
return rippleDrawable;
}
In my custom renderer I assign the drawable
this.Control.Foreground = DrawableHelper.CreateRippleDrawable(this.Context);
and update the ripple when the user touches the control
private void LinkLabelRenderer_Touch(object sender, TouchEventArgs e)
{
if (e.Event.Action == MotionEventActions.Down)
{
this.Pressed = true;
}
if (e.Event.Action == MotionEventActions.Cancel)
{
this.Pressed = false;
}
if (e.Event.Action == MotionEventActions.Up)
{
this.Ripple.SetHotspot(e.Event.GetX(), e.Event.GetY());
this.Pressed = false;
// raise the event of the Xamarin.Forms control
}
}
Now, whenever I click the control, the ripple will be shown, which is the expected behavior, but if I touch (tap or long-press) the parents of the control (e.g. the StackLayout, Grid or whatever layout contains the label, including their parent Layout, Page or View) the ripple animation will be triggered. Anyway, the event handler LinkLabelRenderer_Touch in not called in this case, only when the actual control is touched.
I can work around this behavior by adding an empty GestureRecognizer to the respective parent(s), but I really dislike this solution, because this is but a hack. And to make things worse it is a hack I'll always have to remember whenever I use the control.
How can I prevent the RippleDrawable being shown when the parent is touched?
Turned out I got things fundamentally wrong. Subscribing the Touch event is not the way to go. I had to make the control clickable and subscribe the Click event
this.Control.Clickable = true;
this.Click += LinkLabelRenderer_OnClick;
There is no need to handle all that RippleTouch stuff the way I did (via the Touch event) but could let android handle things for me.

Xamarin Forms add new controls dinamically in the content via code

I have a form in my Xamarin project that its result is something like that:
Basically there is a header (1) and a body of this form (2). The header is quite simple build with AbsoluteLayout.
For creating the body (2) I've created my component to show a tab control and then for each tab a specific grid with images and text. For each section, I'm checking in the database how many records there are for it and change the text. This activity is very long and I'm trying to understand why and how I can improve speed.
Then I should cut the corner to add later in my page the tab control so the user can see immediately the header and after few second all page. The code is like the following:
public class MyPage : WaitingPage
{
public MyPage(Card card)
{
LoadingMessage = "Loading...";
ShowLoadingFrame = true;
ShowLoadingMessage = true;
ShadeBackground = true;
WaitingOrientation = StackOrientation.Vertical;
IsWaiting = true;
StackLayout stackPage = new StackLayout() {
BackgroundColor = Color.FromHex("#fff"),
Children = {
ShowHeader(card),
}
};
Content = stackPage;
Task.Yield();
Task.Run(async () => {
Content = await ShowDetails(card);
});
IsWaiting = false;
}
}
I tried different ways to add the content from await ShowDetails(card); but nothing happens. Basically the content doesn't change unless await ShowDetails(card); is executed. I discovered Task.Yield(); (you can wait the page is rendered and showed and then continue) but in this case doesn't work. And also WaitingPage doesn't show the message.
Any suggestions or help? Thank you in advance

fix java.lang.NullPointerException in the code

I am getting NullPointerException in the code for contextmenu.
here is the onCreateContextmenu Method
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
menu.add(0, MENU_EDIT, 0, "Edit");
menu.add(0, MENU_DELETE, 0, "Delete");
}
I am getting the error in the line long buttonId = info.id; in the code below
public boolean onContextItemSelected(MenuItem item) {
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
long buttonId = info.id;
switch (item.getItemId()) {
case MENU_EDIT:
function1(buttonId);
break;
case MENU_DELETE:
function2(buttonId);
break;
}
return true;
}
Can some one help me fix this
view isn't passed to onContextItemSelected and
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
long buttonId = info.id;
This code doesn't help because menuInfo is null when view is a button. The Android doc says "menuInfo Extra information about the item for which the context menu should be shown. This information will vary depending on the class ofv". When v is a ListView menuInfoapproach is fine. When it is a Button, it doesn't work.
In onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo), the View v is the button that produced the context menu. Copyv to a global View varaiable and use that where you need to have the view of the button that produced the context menu.
How to get the Button view which triggered a Context Menu?

Silverlight DataGrid with vertical Scrollbar problem

I have a Datagrid filled with a table. Now the vertical scrollbar shows up because the table doesn't fit. That's fine so far. Now in the last column I have defined a Button in the xaml file. All these buttons have the same callback, but I can distinguish from the selectedIndex of the table what this callback should do. Because clicking the button automatically also selects the line in the DataGrid where this button lives. That's fine so far. Now in my app, for some rows I want to disable the Button, because it has no meaning for that specific row. So what I did is take a subscription on event Load of each Button and let the callback set the MaxWidth = 0, if the button has no meaning. This works fine too, but only initially. As soon as I start dragging the scrollbar, at random places in the Button column buttons show up, or wrong buttons get MaxWidth = 0. I have the strong feeling that cells that scrolled out at the top are being reused at the bottom, but I don't get an event, or at least I don't know which event I should subscribe on. I don't know how to identify the scrollbar. Has anyone a suggestion to tackle this problem?
I finally found a solution to this problem myself, and I will post it for the record.
The event you should subscribe on is LoadingRow (generated by the DataGrid).
In the callback
void TableLoadingRow(object sender, DataGridRowEventArgs e)
you can identify an element in a cell by using VisualTreeHelper for instance as follows:
private void ButtonSetMaxWidth(DependencyObject reference, int maxWidth)
{
if (reference != null)
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(reference); i++)
{
var child = VisualTreeHelper.GetChild(reference, i);
if (child.GetType() == typeof(Button))
{
Button b = (Button)child;
if (b.Name == "TheNameOfTheButtonInTheXAML")
{
b.MaxWidth = maxWidth;
return;
}
}
ButtonSetMaxWidth(child, maxWidth);
}
}
return;
}

Resources