How to make the BindableLayout to be scrollable - xamarin

I have one list and i don't want to use listview inside it as how can i make it scrollable, data is binding but i am not able to scroll it.
<Grid Grid.Row="0" IsVisible="{Binding SearchListLayout}" Margin="0" Padding="0" BackgroundColor="White">
<ScrollView>
<StackLayout BindableLayout.ItemsSource="{Binding ProductsList}" x:Name="SearchLayoutItemList" HeightRequest="255">
<BindableLayout.ItemTemplate>
<DataTemplate>
<Grid RowDefinitions="37,Auto">
<Image Grid.Row="0" Source="searchingicon.png" Style="{DynamicResource icons}"/>
<Label Grid.Row="0" Text="{Binding name}" FontSize="14" TextColor="Black" Margin="50,0,0,0" HorizontalOptions="StartAndExpand" VerticalOptions="CenterAndExpand"/>
<Image Grid.Row="0" Source="reload.png" Style="{DynamicResource icons}" HorizontalOptions="EndAndExpand" Margin="0,0,15,0"/>
<BoxView Grid.Row="1" Style="{DynamicResource DarkSeparator}" />
</Grid>
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
</ScrollView>
</Grid>

Although the BindableLayout technically can display your list of items via the StackLayout, and the StackLayout height is being restraint to your height request; the encompassing ScrollViewer has nothing to scroll since it fully contains your StackLayout.
To achieve what you probably want (a fixed 255 pixel StackLayout that scrolls your items) the ScrollViewer should be inside the StackLayout as the rendered ItemsPanel for you Items. Again, you could achieve this with custom BindableLayouts, but this is exactly what Xamarin Forms ListView does by default.
You probably simply want to change your BindableLayout implementation to a ListView:
<Grid Grid.Row="0" IsVisible="{Binding SearchListLayout}" Margin="0" Padding="0" BackgroundColor="White">
<ListView ItemsSource="{Binding ProductsList}" x:Name="SearchLayoutItemList" HeightRequest="255">
<ListView.ItemTemplate>
<DataTemplate>
<Grid RowDefinitions="37,Auto">
<Image Grid.Row="0" Source="searchingicon.png" Style="{DynamicResource icons}"/>
<Label Grid.Row="0" Text="{Binding name}" FontSize="14" TextColor="Black" Margin="50,0,0,0" HorizontalOptions="StartAndExpand" VerticalOptions="CenterAndExpand"/>
<Image Grid.Row="0" Source="reload.png" Style="{DynamicResource icons}" HorizontalOptions="EndAndExpand" Margin="0,0,15,0"/>
<BoxView Grid.Row="1" Style="{DynamicResource DarkSeparator}" />
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>

The scrollview could not scroll as you set the HeightRequest="255" for the stacklayout in the scrollview. That because the display content's height is equal with the Scrollview, left content was covered.
Then I remove the HeightRequest
in StackLayout, the ScrollView could scroll. But the scrollview will fill the whole page which I thought is not what you want. So you could add parent layout Stacklayout outside the scrollview which set the size of scrollview equal to 255 and let it scroll at the same time. I just made an example :
<StackLayout>
<ScrollView HeightRequest="255">
<StackLayout BindableLayout.ItemsSource="{Binding ItemCollection}" x:Name="SearchLayoutItemList" >
<BindableLayout.ItemTemplate>
<DataTemplate>
<Grid RowDefinitions="37,Auto">
<Image Grid.Row="0" Source=""searchingicon.png"" />
<Label Grid.Row="0" Text="{Binding name}" FontSize="14" TextColor="Black" Margin="50,0,0,0" HorizontalOptions="StartAndExpand" VerticalOptions="CenterAndExpand"/>
<Image Grid.Row="0" Source="reload.png" HorizontalOptions="EndAndExpand" Margin="0,0,15,0"/>
<BoxView Grid.Row="1" BackgroundColor="Yellow"/>
</Grid>
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
</ScrollView>
</StackLayout>
For more info, you could refer to Xamarin.Forms ScrollView.
Hope it works for you.

Related

Why only the second Frame shows in a StackLayout

I have a Stacklayout that contains another Stacklayout and an Image. In order to have rounded corners for both children of the top Stacklayout, I added Frame for each child. Now, only the second child (Image) appear no matter how I change the visibility of the two children.
<StackLayout HeightRequest="135" WidthRequest="100" Margin="5,5" Grid.Row="0" Spacing="0" HorizontalOptions="Start" VerticalOptions="Start">
<Frame IsVisible="false" CornerRadius="5" IsClippedToBounds="True" Padding="0" HasShadow="False" x:Name="InitialsFrame">
<StackLayout IsVisible="false" HeightRequest="100" WidthRequest="100" BackgroundColor="{Binding Color}">
<Label FontSize="60" Text="{Binding Initials}" TextColor="White" HorizontalOptions="Center" VerticalOptions="CenterAndExpand" HorizontalTextAlignment="Center" VerticalTextAlignment="Center" MaxLines="1" x:Name="InitialsLabel">
</Label>
</StackLayout>
</Frame>
<Frame IsVisible="true" CornerRadius="5" IsClippedToBounds="True" Padding="0" x:Name="ImageFrame">
<Image IsVisible="true" Source="{Binding Image}" HeightRequest="100" WidthRequest="100" x:Name="IconImage" />
</Frame>
</StackLayout>
Without the two Frames, I could choose which child to appear by setting IsVisible to True. But now, setting IsVisible does not work any more. Is there another way to conditionally choose which child to appear?

CollectionView disabling scrolling in Xamarin forms

I am trying to disable scrolling in my collection view. The reason why I want to do that is there is a scroll view already in my XAML code. When I try to scroll all page elements on the page, collection view elements are also scrolled themselves but I don't want that.
<ScrollView>
<StackLayout Padding="20" Spacing="20" >
<Frame CornerRadius="15"
BackgroundColor="#A6EDB3"
VerticalOptions="StartAndExpand"
HeightRequest="200"
IsClippedToBounds="True"
Padding="0" >
<StackLayout Padding="10,5,10,5"
Orientation="Horizontal" >
<Image Source="settingsIcon"
HeightRequest="25"
WidthRequest="25"
Aspect="Fill" />
<Label Text="Filter"
FontSize="Medium"
VerticalTextAlignment="Center"
VerticalOptions="Center"/>
</StackLayout>
</Frame>
<Label Text="Vocabulary topics" TextColor="black" FontSize="20" FontAttributes="Bold" ></Label>
<CollectionView x:Name="topics" Scrolled="topics_Scrolled" VerticalScrollBarVisibility="Never" >
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout Padding="0,10,0,10">
<Frame HasShadow="False"
HeightRequest="60"
CornerRadius="15"
BackgroundColor="{Binding BackgroundColor}"
HorizontalOptions="Fill" >
<StackLayout Orientation="Horizontal">
<Frame BackgroundColor="{Binding BoxColor}" WidthRequest="40" ></Frame>
<StackLayout>
<Label Text="{Binding Name}"></Label>
</StackLayout>
</StackLayout>
</Frame>
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</StackLayout>
</ScrollView>
Having two scrolls on the same page is not the correct way.
Also if you just want to place items above/below your collectionView use the Header/Footer properties then!!
For instance, for the current design, your CollectionView could look something like below and work as you want it to.
<CollectionView Padding="20" x:Name="topics" Scrolled="topics_Scrolled" VerticalScrollBarVisibility="Never" >
<CollectionView.Header>
<StackLayout Spacing="20" >
<Frame CornerRadius="15"
BackgroundColor="#A6EDB3"
VerticalOptions="StartAndExpand"
HeightRequest="200"
IsClippedToBounds="True"
Padding="0" >
<StackLayout Padding="10,5,10,5"
Orientation="Horizontal" >
<Image Source="settingsIcon"
HeightRequest="25"
WidthRequest="25"
Aspect="Fill" />
<Label Text="Filter"
FontSize="Medium"
VerticalTextAlignment="Center"
VerticalOptions="Center"/>
</StackLayout>
</Frame>
<Label Text="Vocabulary topics" TextColor="black" FontSize="20" FontAttributes="Bold" ></Label>
</StackLayout>
</CollectionView.Header>
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout Padding="0,10,0,10">
<Frame HasShadow="False"
HeightRequest="60"
CornerRadius="15"
BackgroundColor="{Binding BackgroundColor}"
HorizontalOptions="Fill" >
<StackLayout Orientation="Horizontal">
<Frame BackgroundColor="{Binding BoxColor}" WidthRequest="40" ></Frame>
<StackLayout>
<Label Text="{Binding Name}"></Label>
</StackLayout>
</StackLayout>
</Frame>
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
Note: you might have to adjust the margin and padding properties for it to look the exact same. My code is just an example.
For more information on CollectionView check: https://learn.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/collectionview/
You can use InputTransparent.
In your case what I would do would be to wrap the CollectionView in a <ContentView> as:
<ContentView InputTransparent="True"
x:Name="content">
<CollectionView ItemsSource="{Binding Items}"...>
...
</CollectionView>
</ContentView>
Create a scroll event to your scroll view:
<ScrollView Scrolled="ScrollView_Scrolled">
...
</ScrollView>
Then, with this event, make sure that the InputTransparent switches depending on the scroll position:
private void ScrollView_Scrolled(object sender, ScrolledEventArgs e)
{
var scrollView = sender as ScrollView;
// Get the height of your scroll view
var contentSize = scrollView.ContentSize.Height;
// Get the max position of the scrollview
var maxPos = contentSize - scrollView.Height;
// Compare it to the current position
if (Convert.ToInt16(e.ScrollY) >= Convert.ToInt16(maxPos))
{
// Switch input transparent value
content.InputTransparent = false;
}
else if (Convert.ToInt16(e.ScrollY) == 0)
{
content.InputTransparent = true;
}
}
This is perfectly fine to use two scrollable controls on the same page for what you want to do. And I don't think <CollectionView.Header> would give you the result you want.
I hope it was helpful! 🙂

How to make Scrollable Label in List Xamarin Forms

I have a List view with fixed Row Height. Inside List view there is Label with large description. I am trying to make this label scroll able. Can anyone help please.
<ListView ItemsSource="{Binding ServiceList, Mode=TwoWay}" RowHeight="100">
<ListView.ItemTemplate>
<DataTemplate x:DataType="models:ServiceModel">
<ViewCell>
<ScrollView
Margin="0"
Padding="0"
HeightRequest="50">
<Label
LineBreakMode="WordWrap"
Style="{StaticResource blackColorLabel}"
Text="{Binding ServiceDescription}" />
</ScrollView>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
As mentioned in the comments, you shouldn't nest scrollviews because the behavior is erratic. You can use BindableLayout though.
<StackLayout BindableLayout.ItemsSource="{Binding ServiceList}">
<BindableLayout.ItemTemplate>
<DataTemplate x:DataType="models:ServiceModel">
<ScrollView
Margin="0"
Padding="0"
HeightRequest="50">
<Label
LineBreakMode="WordWrap"
Style="{StaticResource blackColorLabel}"
Text="{Binding ServiceDescription}" />
</ScrollView>
</DataTemplate>
</BindableLayout.ItemTemplate>
RowHeight is not a thing for BindableLayouts, but you could probably wrap your Label in a ContentView and set the HeightReqeust of the ContentView to 100. Or maybe even just set your Label Height Request to 100 and see what that does.

How to add an Image side to the back button in navigation bar

I am working on xamarin. form application, where I need to add a image side to the
back button in the navigation bar.
I have tried
1. <NavigationPage.TitleView><image/></NavigationPage.TitleView> -here the view is away from the back button. the space between back button and image is more.
2. created a custom navigation as following.
<Grid BackgroundColor="{Binding ActionbarColor}">
<StackLayout Orientation="Horizontal" Spacing="0" HeightRequest="60" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">
<Image Source="back.png" HeightRequest="20" WidthRequest="20" HorizontalOptions="Start" VerticalOptions="CenterAndExpand">
<Image.GestureRecognizers>
<TapGestureRecognizer Command="{Binding MoveBackCommand}"></TapGestureRecognizer>
</Image.GestureRecognizers>
</Image>
<Imge Source="defaultUser.png">
<Label />
<Label x:Name="TitleLabel" VerticalTextAlignment="Center" VerticalOptions="CenterAndExpand" TextColor="White" FontAttributes="Bold" FontSize="Medium" HorizontalOptions="FillAndExpand"/>
</StackLayout>
</Grid>
with 2nd, the view is blinking while navigating to the back view.
Apart of these two are there any ways to display the image in the navigation bar side the back button
Use Grid to Change
<Grid VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand" ColumnSpacing="0">
<Grid.RowDefinitions>
<RowDefinition Height="50"/>
</Grid.RowDefinitions>
<BoxView BackgroundColor="Aqua" Grid.Column="0" Grid.Row="0" Grid.ColumnSpan="5"/>
<Button Image="BackIcon" Grid.Column="0" Grid.Row="0" Grid.ColumnSpan="1" Command="GoBack"/>
<Image Source="Logo" Aspect="AspectFit" BackgroundColor="Transparent" Grid.Column="2" Grid.Row="0" Grid.ColumnSpan="1"/>
</Grid>
It not works follow this - if it works let me know

AutoScale Label Xamarin

I am working on an app that displays results from a RSS feed. I am trying to show the Title and the Date in the same row of a Stacklayout.
Xaml Code:
StackLayout>
<Label Text="60 Second Sports" FontAttributes="Bold" HorizontalOptions="Center"/>
<ListView x:Name="mainArticleRssList" IsPullToRefreshEnabled="True" Refreshing="ListItems_Refreshing" ItemTapped="RssList_ItemTapped">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Padding="15,0,15,0">
<Label Text="{Binding Title}"
LineBreakMode="WordWrap"
MaxLines="2"/>
<Label Text="{Binding PublishedDate}"
LineBreakMode="WordWrap"
MaxLines="1"/>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<controls:AdMobView />
</StackLayout>
Here is what it looks like:
What I Expect:
I want the Title to auto scale to fit in the same row as the date. Is it possible to set a width for the entire row and then have the two labels fit inside of the row?
Other fruits of a few hours of googling:
Here are some of the links I found, but some are old and not sure if they work.
This one is old Auto Scale Text Size
This one didn't work Auto-scaling label fontsize in Xamarin
I also found a couple Nuget packages, but i don't think i need to do that.
https://baskren.github.io/Forms9Patch/
https://forums.xamarin.com/discussion/43468/autosize-font-label
Use Grid Layout inside stack layout to achive it
<ListView x:Name="mainArticleRssList" IsPullToRefreshEnabled="True" HasUnevenRows="True" Refreshing="ListItems_Refreshing" ItemTapped="RssList_ItemTapped">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Padding="15,0,15,0">
<Grid x:Name="grd">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="7*"/>
<ColumnDefinition Width="3*"/>
</Grid.ColumnDefinitions>
<Label Text="{Binding Title}"
LineBreakMode="WordWrap"
MaxLines="2"/>
<Label Text="{Binding PublishedDate}" Grid.Column="1"
LineBreakMode="WordWrap"
MaxLines="1"/>
</Grid>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Use this code and it will work for you.
Is that your needs like this screenshot?
You can use Grid to achieved that.
<ContentPage.Content>
<StackLayout>
<Label Text="Xamarin.Forms native cell" HorizontalTextAlignment="Center" />
<ListView x:Name="listView" CachingStrategy="RecycleElement"
ItemSelected="OnItemSelected">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="3*" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<Label Text="{Binding Title}" Grid.Row="0" Grid.Column="0"
LineBreakMode="TailTruncation"
MaxLines="2" />
<Label Text="{Binding PublishedDate}" Grid.Row="0" Grid.Column="1"
LineBreakMode="WordWrap"
MaxLines="1"/>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage.Content>
If title is too long, you can setLineBreakMode="TailTruncation" it will automatically truncate when the label reaches the end of the container.

Resources