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

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.

Related

Xamarin - bind custom view content

I have created a custom view and I would like to set its content by binding. This is what I have:
<ContentView.Content>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="30"/>
</Grid.ColumnDefinitions>
<ffimageloadingsvg:SvgCachedImage Source="resource://CTP.SVG.exit.svg"
Grid.Row="0" Grid.Column="1"
HeightRequest="30"
WidthRequest="30"
HorizontalOptions="Center"
VerticalOptions="Center">
</ffimageloadingsvg:SvgCachedImage>
<redefinitions:BindableView Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2"
Content="{Binding View, Source={x:Reference this}, Mode=OneWay}"/>
</Grid>
</ContentView.Content>
And following this tutorial I have defined my BindableView:
[ContentProperty(nameof(Content))]
public class BindableView : View
{
public static readonly BindableProperty ContentProperty =
BindableProperty.Create(
propertyName: nameof(Content),
returnType: typeof(View),
declaringType: typeof(BindableView),
defaultValue: default(View));
public View Content
{
get { return (View)GetValue(ContentProperty); }
set { SetValue(ContentProperty, value); }
}
}
But the BindableView is never showing, even if I define its Content statically.
What am I missing?
Easiest way to solve it is to use ContentView instead the custom BindableView.

Invisible Control becomes Visible when closing page Xamarin Forms

I have a frame, the IsVisible is binded to a property in my model view that is set to false. when I change the flyout in my shell, the frame makes an appearance as the shell flyout is closing. Any idea why this is happening ?
// in my model view this is the property
public bool ShowPanel{ get { return _showPanel; } set { _showPanel =
value; OnPropertyChange(); } }
// in my view this is the panel
<Frame IsVisible="{Binding ShowPanel}" BackgroundColor="White" BorderColor="Purple" AbsoluteLayout.LayoutFlags="PositionProportional" WidthRequest="100" HeightRequest="200" AbsoluteLayout.LayoutBounds="0,0,200,250">
<local:ExtendedListView ItemTapped="ExtendedListView_ItemTapped" ItemsSource="{Binding AllItems}" IsVisible="{Binding ShowPanel}" SelectionMode="None" HorizontalScrollBarVisibility="Always" HorizontalOptions="Fill" VerticalOptions="Fill" BackgroundColor="Transparent">
<local:ExtendedListView.ItemTemplate >
<DataTemplate>
<ViewCell>
<Grid Padding="0">
<Grid.RowDefinitions>
<RowDefinition Height="20" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="10*"></ColumnDefinition>
<ColumnDefinition Width="10*"></ColumnDefinition>
<ColumnDefinition Width="20*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Image Grid.Column="0" Image.Source="{Binding ImageUrl}" HorizontalOptions="FillAndExpand" VerticalOptions="CenterAndExpand" WidthRequest="50" HeightRequest="50" x:DataType="local1:ServiceLayers"></Image>
<CheckBox Grid.Column="1" IsChecked="{Binding IsVisible, Mode=TwoWay}" Color="Purple" VerticalOptions="Center" HorizontalOptions="Center" x:DataType="local1:ServiceLayers"></CheckBox>
<Label Padding="-5,0,0,0" HorizontalOptions="StartAndExpand" FontAttributes="Bold" TextColor="Black" Grid.Row="0" Grid.Column="2" HorizontalTextAlignment="Start" Text="{Binding Name}" x:DataType="local1:Service"></Label>
<Label></Label>
</Grid>
</ViewCell>
</DataTemplate>
</local:ExtendedListView.ItemTemplate>
</local:ExtendedListView>
</Frame>
// In the View Class
protected override bool OnBackButtonPressed() {
await Shell.Current.GoToAsync($"//{nameof(MainPage)}");
return true;
}
If the BindingContext is removed/changed as you navigate away from the page, the Frame would appear as the binding is invalidated and updated by the binding engine. You have two options:
Don't manually clear the BindingContext from the page as the navigation lifecycle and GC should clean up those resources on their own.
Use binding fallbacks to define behavior when the binding source can't be resolved (because you've nulled the BindingContext) or the binding source is resolved but the bound property is null.

Xamarin Portable Comments Stacklayout height problems Listview

I am having trouble with height problems in Xamarin PCL with Listview. I want to create a comments section in a scrollable page. But i am struggling with the height of the comments. It just wont expand.
Row.Definition = Auto for the Grid:
<StackLayout Grid.Row="4" Padding="0,20,0,0">
<ListView ItemsSource="{Binding CommentsMVVM}" HasUnevenRows="True">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<local:CommentsRow />
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
In the CommentsRow template:
<Grid RowSpacing="0" ColumnSpacing="14" Padding="20" VerticalOptions="FillAndExpand">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Image Grid.Column="0" Grid.RowSpan="3" Source="{ Binding Image }" VerticalOptions="Start" />
<Label Grid.Column="1" Grid.Row="0" Text="{ Binding UserName }" VerticalOptions="EndAndExpand" TextColor="Blue" />
<Label Grid.Column="1" Grid.Row="1" Margin="0,4,0,0" Text="{ Binding CreatedAt }" TextColor="Grey" FontSize="13" />
<StackLayout Grid.Column="1" Grid.Row="2" Spacing="30" x:Name="StackLayoutMap" VerticalOptions="FillAndExpand" />
</Grid>
And at the C#:
public CommentsRow()
{
InitializeComponent();
var html_label = new HtmlFormattedLabel()
{
TextColor = Color.Black,
FontSize = Device.GetNamedSize(NamedSize.Small, typeof(Label)),
};
html_label.SetBinding(HtmlFormattedLabel.TextProperty, "Memo");
this.StackLayoutMap.Children.Add(html_label);
}
But the StackLayout comments text just wont expand automatically. What am i doing wrong?

How to do the image fill the text - the same size always - xamarin.forms

I am trying to do a button with a image, and each button has a text inside...but I don't know so much about xamarin forms, I'm a beginner
And my images is little while the text is bigger than it...
I am using a grid...and inside it one other grid with 1 colunm and 1 row for each button (Image and texts)
I neet the image (that is my button) get the size of the texts that is inside it
My xml at the moment:
<!-- Buttons grid-->
<Grid HorizontalOptions="Center" Margin="20,20,20,20" RowSpacing="30" ColumnSpacing="10" BackgroundColor="Aquamarine" VerticalOptions="FillAndExpand">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<!--One of my buttons grid, there are 4 others as this one-->
<Grid Grid.Column="0" Grid.Row="1" BackgroundColor="Gray">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Image Source="comochegarbtn.png" HorizontalOptions="FillAndExpand" Grid.Row="0" Grid.Column="0">
<Image.GestureRecognizers>
<TapGestureRecognizer Tapped="MapaClique"/>
</Image.GestureRecognizers>
</Image>
<StackLayout Grid.Row="0" Grid.Column="0" HorizontalOptions="Center" VerticalOptions="Center">
<Image Source="Location.png" VerticalOptions="FillAndExpand"/>
<Label Text="Como Chegar" TextColor="White" HorizontalOptions="Center" Style="{Binding labelsfont}"/>
</StackLayout>
</Grid>
</Grid>
In android I could solve that using wrap_content
But here, in xamarin forms, I don't know how to solve it
The gray part is the grid item size
If you need the exact size of the Text to be the width of your Image then you will have to use RelativeLayout.
In the RelativeLayout for the Image width use RelativeToView.
This is similar to the Relative Layout in Android.
<RelativeLayout>
<Image RelativeLayout.WidthConstraint="{ConstraintExpression Type=Type=RelativeToView, ElementName=myStacklayout,Property=Width,Factor=1}" Source="comochegarbtn.png" HorizontalOptions="FillAndExpand" Grid.Row="0" Grid.Column="0">
<Image.GestureRecognizers>
<TapGestureRecognizer Tapped="MapaClique"/>
</Image.GestureRecognizers>
</Image>
<StackLayout x:Name="myStacklayout" HorizontalOptions="Center" VerticalOptions="Center">
<Image Source="Location.png" VerticalOptions="FillAndExpand"/>
<Label Text="Como Chegar" TextColor="White" HorizontalOptions="Center" Style="{Binding labelsfont}"/>
</StackLayout>
</RelativeLayout>
Using one or 2 relative layouts won't affect you much. But if you think it does you can write a custom render and create a complex button in the native layer.

Horizontal scrollview in XAML

I have a list of MyClass:
public class MyClass
{
public int Id { get; set; }
public string Name { get; set; }
public string Type { get; set; }
}
I would like to display this list in a Horizontal scrollview. Im doing it in XAML and having a hard time finding examples. I got this now:
<ScrollView Orientation="Horizontal">
<ListView x:Name="MyClassList"
ItemsSource="{Binding MyClassList}"
RowHeight="210">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid Padding="5">
<Grid.RowDefinitions>
<RowDefinition Height="20"></RowDefinition>
<RowDefinition Height="20"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"></ColumnDefinition>
<ColumnDefinition Width="1*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0" Text="Name:" LineBreakMode="TailTruncation"></Label>
<Label Grid.Row="0" Grid.Column="1" Text="{Binding Name}" LineBreakMode="TailTruncation"></Label>
<Label Grid.Row="1" Grid.Column="0" Text="Type:" LineBreakMode="TailTruncation"></Label>
<Label Grid.Row="1" Grid.Column="1" Text="{Binding Type}" LineBreakMode="TailTruncation"></Label>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ScrollView>
But this presents the list in a vertical manner. Any tips on how to scroll this list horizontally?
Not entirely sure if I understand the issue. My interpretation is that you want the ListView itself to add elements horizontally instead of vertically.
This can be achieved by settings the ListViews ItemsPanel to a horizontal StackPanel.
Try this:
<ScrollView Orientation="Horizontal">
<ListView x:Name="MyClassList"
ItemsSource="{Binding MyClassList}"
RowHeight="210">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"></StackPanel>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid Padding="5">
<Grid.RowDefinitions>
<RowDefinition Height="20"></RowDefinition>
<RowDefinition Height="20"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"></ColumnDefinition>
<ColumnDefinition Width="1*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0" Text="Name:" LineBreakMode="TailTruncation"></Label>
<Label Grid.Row="0" Grid.Column="1" Text="{Binding Name}" LineBreakMode="TailTruncation"></Label>
<Label Grid.Row="1" Grid.Column="0" Text="Type:" LineBreakMode="TailTruncation"></Label>
<Label Grid.Row="1" Grid.Column="1" Text="{Binding Type}" LineBreakMode="TailTruncation"></Label>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ScrollView>
This has been solved with a custom class called ItemsView (not to be confused with Xamarin's ItemsView for data templating in a ListView) which implements a ScrollView/StackPanel pattern. Please see the code: https://gist.github.com/fonix232/b88412a976f67315f915