Xamarin Forms Shell: Dynamically remove FlyoutFooter - xamarin

It seems as though hiding the FlyoutFooter with IsVisible doesn't cause the scrollview for the Flyout Items to resize to take up the unused space.
Example:
Footer declaration in .xaml:
<Shell.FlyoutFooter>
<StackLayout Spacing="0" BackgroundColor="Pink" HeightRequest="200">
<Button x:Name="btnCloseTip"
Text="X"
Clicked="btnCloseTip_Clicked"/>
</StackLayout>
</Shell.FlyoutFooter>
Click handler:
private void btnCloseTip_Clicked(object sender, EventArgs e)
{
var footer = (StackLayout)this.FlyoutFooter;
footer.IsVisible = false;
}
This hides the pink footer, however the space reserved for the footer is not reallocated to the scrollview that contains the items, leaving a 200 unit high empty space below the scrollable list of flyout items. Is there any way to force the flyout menu to redraw/resize after hiding? I have tried setting the layout bounds to a 0,0,0,0 rectangle as well, which also had the same (no-)effect.

Related

XAMARIN Button with Label and image inside / mainpage=navigation page

I am fairly new and inexperienced. I have two questions. First: what would the xaml code in xamarin look like for such a button? The blue one should be the button. The button should contain a text and a picture. So it should also work that when the image or text is clicked, the button is actually clicked.
enter image description here
Second: my app has two sides. The start page is MainPage and the other page is Page1. I can switch to Page1 using a button on MainPage. I looked at a tutorial and in App.xaml.cs "MainPage = new MainPage ();" was made to "MainPage = new NavigationPage (new MainPage ());". Why was that done? Why does the page change via a button click not work differently?
enter image description here
Since it was coded to "MainPage = new NavigationPage (new MainPage ());" , there is a blue bar at the top of my MainPage. How can I remove this bar or make it white?
enter image description here
For the first question:
There is no such control now, but you can do this by using a Frame and adding an Image and Label to it,then you could add a TapGestureRecognizer to the Frame.
like:
<Frame CornerRadius="20" HorizontalOptions="Start" WidthRequest="100" HeightRequest="120" BackgroundColor="Blue" Padding="40">
<StackLayout Orientation="Vertical" >
<Image Source="heart.png"></Image>
<Label Text="hello world" BackgroundColor="Red" ></Label>
</StackLayout>
<Frame.GestureRecognizers>
<TapGestureRecognizer Tapped="TapGestureRecognizer_Tapped">
</TapGestureRecognizer>
</Frame.GestureRecognizers>
</Frame>
handle the click event in code behind:
private void TapGestureRecognizer_Tapped(object sender, EventArgs e)
{
//do something
}
For the second question:
1)To move from one page to another, an application will push a new page onto the navigation stack.The NavigationPage class provides a hierarchical navigation experience where the user is able to navigate through pages, forwards and backwards, as desired. The class implements navigation as a last-in, first-out (LIFO) stack of Page objects.
2)The top blue bar we call it NavigationBar.If you want display it,you could set NavigationPage.SetHasNavigationBar(this, false); in your MainPage.xaml.cs like:
public MainPage()
{
InitializeComponent();
NavigationPage.SetHasNavigationBar(this, false);
}
or set it in the MainPage.xaml like:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
NavigationPage.HasNavigationBar="False"
x:Class="YourNamespace.MainPage">
....
</ContentPage >
You could look at https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/navigation/hierarchical for more details.

Xamarin.Forms - How can I dynamically change the height of my CarouselView?

I have a CarouselView in which I call an object with individual and completely different Views.
The only elements my ContentPage has, are the CarouselView itself, and a bottombar with a gradient above it (notice gradient in following image).
I have done this in a way in which this gradient dissapears when the page's scrolling space becomes 0 (when I have scrolled to the end of the page).
The problem is that when I swipe between items in the CarouselView, the CarouselView always maintains the height of the very first View that is called in.
This means that, in a View with MORE height than the 1st one, when scrolling up (after being at the very bottom, and therefore not showing a gradient) the gradient will only show again once it hits the height value of the 1st page.
In a View with LESS height than the 1st one, the page will allow me to scroll down until I reach the height value of the 1st page, even if there are not enough elements on the page to even need a scroll.
Essentially, what I am asking for, is if there is a way in which I can, in some way, "refresh" the height of the Page every time a scroll is complete to another View in the CarouselView, resolving my height issues in smaller views, and my gradient issues in larger views.
Main ContentPage Code Behind (Gradient)
public double ScrollingSpace
{
get
{
return MainScrollView.ContentSize.Height - MainScrollView.Height;
}
set { }
}
// Removes gradient when scroll is complete
private void OnScrolled(object sender, ScrolledEventArgs e)
{
if (ScrollingSpace <= e.ScrollY) // Touched bottom
EndPageGradient.SetValue(IsVisibleProperty, false); // the view is GONE, not invisible
else
EndPageGradient.SetValue(IsVisibleProperty, true);
}
// Removes gradient if page is not large enough to need scroll
protected override void OnAppearing()
{
if (ScrollingSpace <= 0)
EndPageGradient.SetValue(IsVisibleProperty, false); // the view is GONE, not invisible
}
Main ContentPage CarouselView XAML
<CarouselView
ItemsSource="{Binding ViewList}"
Loop="False">
<CarouselView.ItemTemplate>
<DataTemplate>
<ContentView Content="{Binding .}" />
</DataTemplate>
</CarouselView.ItemTemplate>
</CarouselView>
Main ContentPage ViewModel (List with Views for CarouselView)
ViewList = new List<ContentView>()
{
new Step1(),
new Step2(),
new Step3(),
new Step4(),
new Step5(),
new Step6(),
new Step7(),
new Step8()
};
Thanks in advance!

How to make ActivityIndicator overlay full screen?

I have a StackLayout and a number of elements inside (buttons, texts etc).
I want the ActivityIndicator to overlay the entire screen and make it not able to do anything to those elements.
I have put ActivityIndicator inside the StackLayout but wrapped it with AbsoluteLayout thinking that AbsoluteLayout can easitly overlap everything:
<StackLayout>
<AbsoluteLayout>
<ActivityIndicator ... />
</AbsoluteLayout>
<...other elements...>
</StackLayout>
Instead activity indicator is displayed at the top of the StackLayout and other elements are available for affecting. I'm new in Xamarin and layouts, what am I doing wrong? All samples in the Internet have single ActivityIndicator per page...
It is better said that an AbsoluteLayout's children can easily overlap each other. Just as a StackLayout lets you stack controls inside , vertically or horizontally, an AbsoluteLayout lets you position controls inside using absolute or proportional values, thus if two controls have the same absolute positioning set, they will overlap 100%.
Therefore, you want to wrap your StackLayout and another StackLayout that has your ActivityIndicator inside an AbsoluteLayout using proportional sizing, e.g:
<AbsoluteLayout>
<StackLayout
x:Name="mainLayout"
AbsoluteLayout.LayoutBounds="0,0,1,1"
AbsoluteLayout.LayoutFlags="All" >
<Label Text="Welcome to Xamarin.Forms!"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
<Button Text="Do Something"
Clicked="DoSomethingBtn_Clicked" />
</StackLayout>
<StackLayout
x:Name="aiLayout"
IsVisible="False"
AbsoluteLayout.LayoutBounds="0,0,1,1"
AbsoluteLayout.LayoutFlags="All"
BackgroundColor="Gray" Opacity="0.5">
<ActivityIndicator
x:Name="ai"
IsRunning="False"
HorizontalOptions="CenterAndExpand"
VerticalOptions="CenterAndExpand"
Color="Black"/>
</StackLayout>
</AbsoluteLayout>
The above sets the two StackLayouts to both take up the full size of the parent container of the AbsoluteLayout, which is presumably a Page. The StackLayout that has the indicator is initially hidden. IN the page code behind for the above example, I show the second StackLayout and start the activity indicator and show it for 2 seconds, and then hide it again:
private async void DoSomethingBtn_Clicked(object sender, EventArgs e)
{
ai.IsRunning = true;
aiLayout.IsVisible = true;
await Task.Delay(2000);
aiLayout.IsVisible = false;
ai.IsRunning = false;
}
Here is what it looks like:
And since the second StackLayout completely covers the first, none of the controls in the first StackLayout are clickable.
Might be worth going over the docs for the AbsoluteLayout to understand the AbsoluteLayout.LayoutBounds and AbsoluteLayout.LayoutFlags:
https://learn.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/layouts/absolute-layout
If you want to "overlap", you need to be outside of the StackLayout. A Grid is the most common control for this:
<Grid>
<StackLayout>
<...other elements...>
</StackLayout>
<ActivityIndicator ... />
</Grid>
Here's a hacked-up control for making things full-screen via the horribly-named RelativeLayout (tested in Android only)
[ContentProperty("ContentInner")]
public class FullScreenLayout : ContentView
{
public View ContentInner
{
get => ((RelativeLayout) Content).Children[0];
set
{
var display = DeviceDisplay.MainDisplayInfo;
var screenWidth = display.Width / display.Density;
var screenHeight = display.Height / display.Density;
var wrapper = new RelativeLayout();
wrapper.Children.Add(value, () => new Rectangle(0, 0, screenWidth, screenHeight));
Content = wrapper;
}
}
}
It can be used like this:
<controls:FullScreenLayout>
<!-- Anything you want fullscreen here -->
</controls:FullScreenLayout>
Unfortunately, if you use NavigationPage, this won't overlap the navigation bar. Every other solution currently on this page has the same issue. According to this question, it's not possible to solve this without using platform-specific customer renderers. Ugh.
If you don't mind the page being dimmed, you can use Rg.Plugins.Popup which implements the custom renderers needed.
I ended up solving my similar problem (dimming most of the screen) by implementing a custom renderer for the navigation page itself.

Panorama animation is broken when removing ApplicationBar or changing its visibility or opacity

I have 3 panorama items, and I would like only the 1st to have an app bar.
So I started to implement removing the app bar for the other panorama items.
What I did was to handle SelectionChanged event and based on Panorama.SelectedIndex hide the application bar:
this.ApplicationBar.IsVisible = this.Panorama.SelectedIndex == 0;
When swiping to the 2nd item, the usual panorama animation does not work anymore, the transition animation is gone, it's sudden.
Instead of changing IsVisible, I also tried with the same result:
remove app bar this.ApplicationBar = null
set opacity to zero this.ApplicationBar.Opacity = 0
What's interesting is that animation is broken even if changing opacity to let's say 0.5
My feeling is that layout change event in the app bar generate this Panorama broken behavior.
I haven't yet been able to find a solution.
put the whole panorama in а stackpanel
<StackPanel>
<phone:Panorama Title="my application">
<phone:PanoramaItem Header="first item"/>
<phone:PanoramaItem Header="second item" Tap="OnPanoramaItemTap"/>
</phone:Panorama Title="my application">
</StackPanel>
private void OnPanoramaItemTap(object sender, System.Windows.Input.GestureEventArgs e)
{
ApplicationBar.IsVisible = false;
}
It's just an idea, but it's working, i hope it's good for your case

Get scroll event for ScrollViewer on Windows Phone

Question:
Get scroll event for ScrollViewer on Windows Phone
I have a scrollviewer like so:
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<ScrollViewer x:Name="MyScroller">
<StackPanel>
<!-- ... -->
</StackPanel>
</ScrollViewer>
</Grid>
I need the event for when the scrolling occurs for MyScroller:
// MyScroller.Scroll += // <-- "Scroll" event does not exist on ScrollViewer
MyScroller.MouseWheel += MyScroller_MouseWheel; // Does not fire on scroll
MyScroller.ManipulationDelta += MyScroller_ManipulationDelta; // Fires for pinch-zoom only
MouseMove fires when ScrollViewer is scrolled:
public MainPage()
{
InitializeComponent();
MyScroller.MouseMove += MyScroller_MouseMove;
}
void MyScroller_MouseMove(object sender, MouseEventArgs e)
{
throw new NotImplementedException();// This will fire
}
It isn't intuitive, since it is named as a "mouse" event and there is no mouse on the phone. The touch point does move, however, relative to the ScrollViewer container, which is how it can handle scrolling.
It's not that simple, but there's a few scroll detection mechanisms written in this question:
WP7 Auto Grow ListBox upon reaching the last item
Basically take a look at the way OnListVerticalOffsetChanged is called and used.
With Mango, you can watch for the "ScrollStates" visual state to change as described in this sample project.

Resources