Xamarin - How to display current position in CarouselView control? - xaml

Please help with CarouselView.
Xaml:
<carousel:CarouselViewControl.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Image Source="{Binding ImSource}" Aspect="AspectFill" Grid.Row="0" Grid.RowSpan="3" HeightRequest="220"/>
<Button
Grid.Row="0"
Text="1/1"
CornerRadius ="40"
FontSize="10"
HorizontalOptions="End"
BackgroundColor="Black"
TextColor="White"
WidthRequest="40"
HeightRequest="20"
Margin="0, 10, 10, 0"
Opacity="0.7"
Padding="0"/>
<controls:CircleImage
Grid.Row="2"
Source="users.png"
HorizontalOptions="Start"
WidthRequest="22"
Opacity="0.7"
Margin="10, 0, 0, 10"/>
</Grid>
</DataTemplate>
</carousel:CarouselViewControl.ItemTemplate>
</carousel:CarouselViewControl>
On my Button I need to display current position in Carousel.
But if in list one image - need to hide this button.
Button text must be like - 2(position)/3(list.Count)
I used: https://github.com/alexrainman/CarouselView
Please tell me - how I can do this.

Try to bind carousel position property to your ViewModel and then bind text from ViewModel to your button. So, something like this for CarouselViewControl:
<carousel:CarouselViewControl x:Name="CarouselView"
Position="{Binding CarouselPosition}"
ItemsSource="{Binding CarouselViewItems}">
...
</carousel:CarouselViewControl>
Your Button:
<Button
Grid.Row="0"
Text="{Binding CarouselPositionDisplayCounter}" .../>
In your ViewModel, add properties like it follows.
Carousel's current position:
private int _carouselPosition;
public int CarouselPosition
{
get { return _carouselPosition; }
set
{
_carouselPosition = value;
OnPropertyChanged();
}
}
Text binded to button:
public string CarouselPositionDisplayCounter =>
$"{(CarouselPosition + 1).ToString()}/{CarouselViewItems.Count.ToString()}";
And command when swiped:
public ICommand CarouselSwipedCommand => new Command(() =>
{
OnPropertyChanged(nameof(CarouselPositionDisplayCounter));
});

The carouselView already comes with it's own implementation of what you want:
You just need to add the ShowIndicators property to your xaml declaration:
<controls:CarouselViewControl ShowIndicators="True" ... />
Also there are properties for specifying shape and color of the indicators:
IndicatorsTintColor: page dot indicators fill color (default #C0C0C0).
CurrentPageIndicatorTintColor: selected page dot indicator fill color (default #808080).
IndicatorsShape: Indicators shape (default Circle).

Related

How to make FlexLayout's height adjust to its content?

In my Xamarin Forms application, I have a list of strings (minimum 1, maximum 4) that I want to display evenly in a column layout. Each column needs to have the same width and the content should expand so that the whole text is wrapped and visible. I know how I can do it using the Grid control using Width="*" on its columns.
I want to achieve the same result using FlexLayout, so I can bind the list of strings to BindableLayout and easily add and remove columns (I will not be displaying strings but a more complex layout in each column).
Using FlexLayout.Grow and FlexLayout.Basis I can get the FlexLayout to display evenly sized columns. The problem is making the FlexLayout's height fit all the displayed labels. Only the first row of text is displayed.
Both the Grid and FlexLayout are wrapped in a StackLayout:
<StackLayout>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Text="First label" Grid.Column="0" BackgroundColor="Aqua"
LineBreakMode="WordWrap" />
<Label Text="Second label" Grid.Column="1" BackgroundColor="Red"
LineBreakMode="WordWrap" />
<Label Text="Third label but with longer text" Grid.Column="2" BackgroundColor="Aqua"
LineBreakMode="WordWrap"/>
<Label Text="Fourth label" BackgroundColor="Red"
Grid.Column="3" LineBreakMode="WordWrap" />
</Grid>
<BoxView BackgroundColor="Blue"></BoxView>
<FlexLayout AlignItems="Stretch">
<Label Text="First label"
FlexLayout.Grow="1"
FlexLayout.Basis="0"
BackgroundColor="Aqua"
LineBreakMode="WordWrap" />
<Label Text="Second label"
FlexLayout.Grow="1"
FlexLayout.Basis="0"
BackgroundColor="Red"
LineBreakMode="WordWrap" />
<Label Text="Third label but with longer text"
FlexLayout.Grow="1"
FlexLayout.Basis="0"
BackgroundColor="Aqua"
VerticalOptions="FillAndExpand"
LineBreakMode="WordWrap" />
<Label Text="Fourth label"
FlexLayout.Grow="1"
FlexLayout.Basis="0"
BackgroundColor="Red"
LineBreakMode="WordWrap" />
</FlexLayout>
<BoxView BackgroundColor="Blue"></BoxView>
</StackLayout>
Grid and FlexLayout displayed
I figured out that when setting the HeightRequest of the FlexLayout to a specific number (e.g. 150), everything works as expected - the row has a height of 150 and all the labels stretch out to fit that. So what I need is somehow specify HeightRequest="Auto" so that the row fits all the column's content without being set to a specific value
Is there a way to achieve this?
FlexLayout will cut its child Elements . So in your case use Grid is the best solution .
so I can bind the list of strings to BindableLayout and easily add and remove columns
If you want to display a collection of data I suggest that you could use ListView or CollectionView(if you want to let the collection scroll in Horizontal or display multi Columns in the same row) .
<ContentPage.Resources>
<ResourceDictionary>
<local:WidthConverter x:Key="WidthConverter" />
</ResourceDictionary>
</ContentPage.Resources>
<StackLayout x:Name="stack">
<CollectionView x:Name="list" >
<CollectionView.ItemsLayout>
<LinearItemsLayout Orientation="Horizontal" />
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid WidthRequest="{Binding Source={x:Reference stack},Path=Width,Converter={StaticResource WidthConverter}}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Label Text="111111" BackgroundColor="LightBlue" />
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</StackLayout>
in code behind
public class WidthConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var width = (double)value;
if(width>0)
{
return width * 0.25;
}
return 100;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return 0;
}
}
For more details you could check https://learn.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/collectionview/layout#horizontal-list

Hoe to make an ImageButton with a label ontop clickable

So I've run into a problem with Imagebuttons in XAML.
I usually render a background image from photoshop and then use this button everywhere and just add a label ontop that says what it does:
enter image description here
This here for isntance comes from this code (partially):
<!--Grid for button-->
<Grid Grid.Row="1" >
<ImageButton
x:Name="btn_register_mainpage"
Source="btn_emptydummy.png" BackgroundColor="#00000000"/>
<Label
FontFamily="arial"
TextColor="#272727"
Text="Profil erstellen"
HorizontalOptions="Center"
VerticalOptions="Center"/>
</Grid>
Now, this works just fine, unless you want to click on it.
As you can see I gave the button a name, I can now catch that name in code and delegate a click to it:
btn_register_mainpage.Clicked += async delegate
{
await Navigation.PushAsync(new Screen_EditInformation());
};
However, this only works when the user clicks on the button - but NOT on the label since this is on top and has no click assigned to it.
So, what I could do is just assign the same click event to both objects (the label and the image button) but that seems rather unusual.
What is the best way to have a custom image as a button with a label ontop that is clickable?
You can add GestureRecognizers to any control in Xamarin.Forms. In your case you could add one to the Grid layout
YourView.xaml
<Grid Grid.Row="1" >
<Grid.GestureRecognizers>
<TapGestureRecognizer
Tapped="OnTapGestureRecognizerTapped"
NumberOfTapsRequired="1" />
</Grid.GestureRecognizers>
<ImageButton
x:Name="btn_register_mainpage"
InputTransparent="True"
Source="btn_emptydummy.png" BackgroundColor="#00000000"/>
<Label
FontFamily="arial"
TextColor="#272727"
Text="Profil erstellen"
HorizontalOptions="Center"
VerticalOptions="Center"/>
</Grid>
YourView.xaml.cs
private void OnTapGestureRecognizerTapped(object sender, EventArgs e)
{
Navigation.PushAsync(new Screen_EditInformation());
}
You could add a TapGestureRecognizer on the label .
<Grid Grid.Row="1" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="40"/>
</Grid.RowDefinitions>
<ImageButton
Clicked="Button_Clicked"
Grid.Row="0"
x:Name="btn_register_mainpage"
BackgroundColor="LightBlue"/>
<Label
Grid.Row="0"
FontFamily="arial"
TextColor="#272727"
Text="Profil erstellen"
HorizontalOptions="Center"
VerticalOptions="Center">
<Label.GestureRecognizers>
<TapGestureRecognizer
Tapped="Button_Clicked"
NumberOfTapsRequired="1" />
</Label.GestureRecognizers>
</Label>
</Grid>

Editor goes behind the keyboard when it resized using Wordwrap in Xamarin.Forms (iOS)?

I am proceeding further and generating new ticket as it is quite different from this issue How to prevent Editor to go behind the keyboard in Xamarin.Forms?
I have chat page and autosize editor. When user type more than 1-2 lines, Editor expand correctly but it goes behind the keyboard.
However, if user add multiple lines using "return" it works correctly. I think I am missing something in Xaml page to play with Editor and StackLayout.
Please suggest
Please note that I don't use Xam.Plugins.Forms.KeyboardOverlap. To manage layout on keyboard visibility, I use custom stacklayout WrapperStackLayoutRenderer which set bottom padding on appear and disappear of keyboard.
Page Xaml
<ContentPage.Content>
<local1:WrapperStackLayout>
<Grid Margin="0" Padding="0" RowSpacing="0">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<ListView x:Name="MessagesListView"
ItemTemplate="{StaticResource MessageTemplateSelector}"
ItemsSource="{Binding Conversations}"
HasUnevenRows="True"
Margin="0"
Grid.Row="0"
SeparatorVisibility="None"/>
<Grid RowSpacing="1" ColumnSpacing="2" Padding="5" Grid.Row="1" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="auto" />
</Grid.ColumnDefinitions>
<local1:EditorWithAutoSize x:Name="txtMessage" Text="{Binding SendingText}" TextChanged="EnableSend"/>
<Frame x:Name="SendButton" Grid.Column="1" Margin= "0" Padding="0" HasShadow="false" HeightRequest="25"
BackgroundColor="Transparent" HorizontalOptions="FillAndExpand">
<Frame.GestureRecognizers>
<TapGestureRecognizer Tapped="SendMessage_Click" NumberOfTapsRequired="1" />
</Frame.GestureRecognizers>
<Label Text="Send" x:Name="sendButton" HeightRequest="20"
HorizontalOptions="Center" VerticalOptions="Center"/>
</Frame>
</Grid>
</Grid>
</local1:WrapperStackLayout>
</ContentPage.Content>
EditorWithAutoSize
public class EditorWithAutoSize : Editor
{
public EditorWithAutoSize()
{
this.TextChanged += (sender, e) => {
this.InvalidateMeasure();
};
}
}
WrapperStackLayout
public class WrapperStackLayout : StackLayout
{
}
WrapperStackLayoutRenderer
public class WrapperStackLayoutRenderer : VisualElementRenderer<StackLayout>
{
public WrapperStackLayoutRenderer()
{
UIKeyboard.Notifications.ObserveWillShow((sender, args) =>
{
if (Element != null)
{
Element.Margin = new Thickness(0, 0, 0, (args.FrameEnd.Height));
}
});
UIKeyboard.Notifications.ObserveWillHide((sender, args) =>
{
if (Element != null)
{
Element.Margin = new Thickness(0); //set the margins to zero when keyboard is dismissed
}
});
}
}
You have to add RowDefinition Height="auto" in your second Grid, then the editor will auto group with the text you entered:
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
The complete code should be:
<Grid RowSpacing="1" ColumnSpacing="2" Padding="5" Grid.Row="1" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand">
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="auto" />
</Grid.ColumnDefinitions>
<local:EditorWithAutoSize x:Name="txtMessage" Text="Binding SendingText" />
<Frame x:Name="SendButton" Grid.Column="1" Margin= "0" Padding="0" HasShadow="false" HeightRequest="25"
BackgroundColor="Transparent" HorizontalOptions="FillAndExpand">
<Label Text="Send" x:Name="sendButton" HeightRequest="20"
HorizontalOptions="Center" VerticalOptions="Center"/>
</Frame>
</Grid>
I uploaded my test sample here and you can check it: editor-xamarin.forms
BTW, there is a sample in github that you can refer: ChatUIXForms, you can use the editor and custom renderer code in his project. There are also blogs the author wrote you can read.

How to fill a button with an image in Xamarin Forms?

I am trying to fill a Button with an Image. The button resides within a Grid. The problem is that the image is not fully filling the button. I have also tried to use the ImageButton control.
Here is how I am building my U.I:
<Grid Grid.Row="1" Grid.Column="1" x:Name="VotingGrid" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="45*" />
<ColumnDefinition Width="10*" />
<ColumnDefinition Width="45*" />
</Grid.ColumnDefinitions>
<Button Grid.Row="0" Grid.Column="0" Image="yay.png" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand"/>
<Button Grid.Row="0" Grid.Column="2" Image="meh.png" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand"/>
</Grid>
It currently looks like the image attached below, but I'd like to image to fill my button.
Any help will be appreciated!
Try to place an image instead of button.
You can make use of Tap Gesture Gesture Recognizer to take click events.
Try something like this :
<Image Source="tapped.jpg">
<Image.GestureRecognizers>
<TapGestureRecognizer
Tapped="OnTapGestureRecognizerTapped" />
</Image.GestureRecognizers>
</Image>
The code for the event handler
void OnTapGestureRecognizerTapped(object sender, EventArgs args) {
var imageSender = (Image)sender;
// Do something
DisplayAlert ("Alert", "Tap gesture recoganised", "OK");
}
Refer : Adding a Tap Gesture Gesture Recognizer
I have not used it myself but maybe you can use this one from XLab
https://github.com/XLabs/Xamarin-Forms-Labs/wiki/ImageButton

Capture Element not using room from parent control

I am trying to create a page with a capture element and a button overlaid on top to take the picture.
The problem I've got is, the capture element won't use up the whole screen. There are bars above and below.
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="100"/>
</Grid.RowDefinitions>
<CaptureElement
Grid.Row="0"
x:Name="capPreview"
Stretch="Uniform"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Tapped="capPreview_Tapped"
/>
<Button Content="Submit"
HorizontalAlignment="Center"
Grid.Row="1"
x:Name="btnTakePicture"
Click="btnTakePicture_Click">
<Button.Background>
<SolidColorBrush Color="Black" Opacity="100"/>
</Button.Background>
<Button.BorderBrush>
<SolidColorBrush Color="White"/>
</Button.BorderBrush>
</Button>
</Grid>
Edit: I have since used the code behind to rotate the capture element, however; upon doing so, the element now just has a box all around it instead of top and bottom.
<CaptureElement
Grid.Row="0"
x:Name="capPreview"
Tapped="capPreview_Tapped"
/>
Short of hard coding the height and width values, I am out of ideas.
It deos use the whole screen, the issue is the orientation of the preview is different than the orientation of the screen.
MediaCapture has a method SetPreviewRotation to handle this issue.
It works for me :) Just grid and Strech, If you want to have focus just make transparent grid outside CaptureElement
<Grid>
<Grid Tapped="SetFocus">
<CaptureElement x:Name="CaptureElement" Stretch="UniformToFill"/>
</Grid>
<Grid VerticalAlignment="Bottom">
<Button x:Name="SaveButton" Foreground="Transparent" IsDoubleTapEnabled="False" Width="48" Height="48" Background="Transparent" BorderBrush="Transparent"
Click="OnSaveButtonClicked" HorizontalAlignment="Stretch" Margin="12,0">
</Button>
</Grid>
</Grid>
Try this one it will capture directly with the button click
private async void Button_Click_3(object sender, RoutedEventArgs e)
{
Uri u = new Uri("ms-data:///local");
StorageFile file = await ApplicationData.Current.LocalFolder.GetFileAsync("Photo.jpg");
IRandomAccessStream st = await file.OpenAsync(FileAccessMode.Read);
BitmapImage image = new BitmapImage();
image.SetSource(st);
img.Source = image;
}
<CaptureElement Name="element" Height="600"/>
<StackPanel>
<Button Content="Capture Image" Click="Button_Click_3"/>
</StackPanel>
<Image Name="img" Margin="0,0,0,0"/>