I'm looking for the best way to change the content of a page, without navigating to a new one.
I tried having two stacklayouts, and on a button press I'd change the IsVisible and IsEnabled properties of each stack layout. Although this worked, I was left with a small white gap at the end of each layout (I believe this is a Xamarin.Forms bug).
What would be the best way to accomplish this task? Is there anything built into Xamarin.Forms that can do this that I have missed?
Here is a little sketch design for you to see what I mean:
Before suggesting I use tabs, I'll add that I already have tabs in the application, the sketch doesn't show that though. I need this navigation to work on only ONE page.
The code I used before, that didn't work is:
(Before anybody mentions the poor naming conventions and lack of content, I had to strip it all out as it's code written for an employer.
C#:
private void Button1_Clicked(object sender, EventArgs e)
{
Content2.IsVisible = false;
Content2.IsEnabled = false;
Content1.IsVisible = true;
Content1.IsEnabled = true;
}
private void Button2_Clicked(object sender, EventArgs e)
{
Content2.IsVisible = true;
Content2.IsEnabled = true;
Content1.IsEnabled = false;
Content1.IsVisible = false;
}
XML:
<ScrollView x:Name="content1" VerticalOptions="FillAndExpand" BackgroundColor="#f2f2f2">
<StackLayout Spacing="0">
<StackLayout Orientation="Horizontal" BackgroundColor="White" Padding="20,20,20,20" HorizontalOptions="FillAndExpand">
<StackLayout>
<Label Text="text:" FontFamily="{StaticResource BoldFont}"/>
<StackLayout Orientation="Horizontal">
<Image x:Name="content1image" HeightRequest="25" WidthRequest="25"/>
<Label x:Name="content1label" FontFamily="{StaticResource Font}" FontSize="27" TextColor="#969696"/>
</StackLayout>
</StackLayout>
<StackLayout HorizontalOptions="FillAndExpand">
<Entry x:Name="content1Entry" Keyboard="Numeric" Margin="0,25,0,0" Placeholder="0.00000000" FontFamily="{StaticResource Font}" FontSize="27" HorizontalOptions="FillAndExpand" HorizontalTextAlignment="End" TextColor="#969696"/>
<Label x:Name="content1Label2" FontSize="14" FontFamily="{StaticResource Font}" HorizontalOptions="FillAndExpand" HorizontalTextAlignment="End" TextColor="#969696"/>
</StackLayout>
</StackLayout>
<StackLayout Padding="20,30,20,0" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">
<Label Text="content1Label3" FontFamily="{StaticResource Font}"/>
<StackLayout Orientation="Horizontal">
<Button x:Name="content1button" Image="image.png" BackgroundColor="Transparent" HorizontalOptions="Start" Margin="0" WidthRequest="25" HeightRequest="25"/>
<Entry x:Name="content1Entry2" FontFamily="{StaticResource Font}" FontSize="12" HorizontalOptions="FillAndExpand" HorizontalTextAlignment="End"/>
</StackLayout>
</StackLayout>
<StackLayout VerticalOptions="EndAndExpand" Padding="0,-1,0,0">
<Label x:Name="content1Label4" FontSize="19" HorizontalOptions="CenterAndExpand" FontFamily="{StaticResource Font}"/>
<Label x:Name="content1Label5" FontSize="12" TextColor="#b6b6b6" HorizontalOptions="CenterAndExpand" FontFamily="{StaticResource Font}"/>
<Button x:Name="content1Button2" VerticalOptions="End" HorizontalOptions="FillAndExpand" BorderRadius="25" BackgroundColor="#2r432d" BorderColor="#2r432d" TextColor="White" FontFamily="{StaticResource Font}" FontSize="20" BorderWidth="3" Margin="10,10,10,10"/>
</StackLayout>
</StackLayout>
I have not had very much success using Stacklayouts. Grids however has a lot of customizability and in my case it expands to fill all the area that you wish for.
This is how I would do it.
Xaml
<Grid x:Name="Grid1" IsVisible="False" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid Grid.Row="0" VerticalOptions="CenterAndExpand" HorizontalOptions="CenterAndExpand">
<Label FontSize="Medium" Text="Grid1 Label"/>
</Grid>
<Grid Grid.Row="1" HeightRequest="100" WidthRequest="375" VerticalOptions="StartAndExpand" HorizontalOptions="CenterAndExpand">
<Button x:Name="btnGrid1"/>
</Grid>
</Grid>
<Grid x:Name="Grid2" IsVisible="False" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid Grid.Row="0" VerticalOptions="CenterAndExpand" HorizontalOptions="CenterAndExpand">
<Label FontSize="Medium" Text="Grid2 Label"/>
</Grid>
<Grid Grid.Row="1" HeightRequest="100" WidthRequest="375" VerticalOptions="StartAndExpand" HorizontalOptions="CenterAndExpand">
<Button x:Name="btnGrid2"/>
</Grid>
</Grid>
Code-behind
private void Button1_Clicked(object sender, EventArgs e)
{
Grid2.IsVisible = false;
Grid1.IsVisible = true;
}
private void Button2_Clicked(object sender, EventArgs e)
{
Grid2.IsVisible = true;
Grid1.IsVisible = false;
}
Related
I am quite new to this, but I am trying to figure out how to dynamically add entries with a button click.
I am creating new entries with each button click but my issue is that the entries are placed under the button instead of ontop of it.
Here is how my app looks like:
[![enter image description here][1]][1]
By clicking the `Add Ingredient` button, I want to add a new entry.
This is what the front end looks like:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="EasyChef.Views.AboutPage"
xmlns:vm="clr-namespace:EasyChef.ViewModels"
Title="{Binding Title}">
<ContentPage.BindingContext>
<vm:AboutViewModel />
</ContentPage.BindingContext>
<ContentPage.Resources>
<ResourceDictionary>
<Color x:Key="Accent">#96d1ff</Color>
</ResourceDictionary>
</ContentPage.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<StackLayout BackgroundColor="{StaticResource Accent}" VerticalOptions="FillAndExpand" HorizontalOptions="Fill">
<StackLayout Orientation="Horizontal" HorizontalOptions="Center" VerticalOptions="Center">
<ContentView Padding="0,40,0,40" VerticalOptions="FillAndExpand">
<Label Text="EasyChef" TextColor="Black" FontSize="24" FontAttributes="Bold" Margin="10"/>
</ContentView>
</StackLayout>
</StackLayout>
<ScrollView Grid.Row="1">
<StackLayout Orientation="Vertical" Padding="30,24,30,24" Spacing="10">
<Label Text="Simply select ingredients!" FontSize="Title"/>
<StackLayout x:Name="EntriesStackLayout">
<Grid VerticalOptions="CenterAndExpand" Margin="20" RowSpacing="20">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Entry Placeholder="Eg. Eggs" x:Name="EntryTag" Grid.Row="0"/>
<Button Text="Add Ingredient" Grid.Row="1" Clicked="Button_Clicked"/>
</Grid>
</StackLayout>
<CheckBox />
</StackLayout>
</ScrollView>
</Grid>
</ContentPage>
And the back end()
public partial class AboutPage : ContentPage
{
int x = 1;
public AboutPage()
{
InitializeComponent();
}
private void Button_Clicked(object sender, EventArgs e)
{
AddEntry(EntriesStackLayout, "Ingredient " + x.ToString());
x++;
}
private void AddEntry(StackLayout sl, string name)
{
Entry entry = new Entry()
{
Placeholder = name,
};
sl.Children.Add(entry);
}
}
My preferred solution would be to create new entries with each button click, but I am happy with having default entries and unhiding them in order with a click.
A simple method is to move the Button to the outside of the StackLayout(StackLayout x:Name="EntriesStackLayout") and below the StackLayout.
Please refer to the following code:
<ScrollView Grid.Row="1">
<StackLayout Orientation="Vertical" Padding="30,24,30,24" Spacing="10">
<Label Text="Simply select ingredients!" FontSize="Title"/>
<StackLayout x:Name="EntriesStackLayout">
<Grid VerticalOptions="CenterAndExpand" Margin="20" RowSpacing="20">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Entry Placeholder="Eg. Eggs" x:Name="EntryTag" Grid.Row="0"/>
<!--<Button Text="Add Ingredient" Grid.Row="1" Clicked="Button_Clicked"/>-->
</Grid>
</StackLayout>
<!--move button here-->
<Button Text="Add Ingredient" Grid.Row="1" Clicked="Button_Clicked"/>
<CheckBox />
</StackLayout>
</ScrollView>
I have a pretty straight forward question.
With this code, I create new entries whenever i click a button:
XAML
<Button Text="Add Ingredient" Grid.Row="1" Clicked="Button_Clicked"/>
Code-behind
private void Button_Clicked(object sender, EventArgs e)
{
AddEntry(EntriesStackLayout, "Ingredient " + x.ToString());
x++;
}
private void AddEntry(StackLayout sl, string name)
{
Entry entry = new Entry()
{
Placeholder = name,
};
sl.Children.Add(entry);
}
I want to know what could I do to then remove these entries in order. For last to first?
This is what the app looks like:
I want to know what could I do to then remove these entries in order.
For last to first?
For your problem, you can remove the last element one by one in your StackLayout(EntriesStackLayout).
Please refer to the following code:
private void Button_Clicked_Remove(object sender, EventArgs e)
{
var element = EntriesStackLayout.Children.LastOrDefault();
if (element!=null) {
EntriesStackLayout.Children.Remove(element);
}
}
YouPage.xaml
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<StackLayout VerticalOptions="FillAndExpand" HorizontalOptions="Fill">
<StackLayout Orientation="Horizontal" HorizontalOptions="Center" VerticalOptions="Center">
<ContentView Padding="0,40,0,40" VerticalOptions="FillAndExpand">
<Label Text="EasyChef" TextColor="Black" FontSize="24" FontAttributes="Bold" Margin="10"/>
</ContentView>
</StackLayout>
</StackLayout>
<ScrollView Grid.Row="1">
<StackLayout Orientation="Vertical" Padding="30,24,30,24" Spacing="10">
<Label Text="Simply select ingredients!" FontSize="Title"/>
<StackLayout x:Name="EntriesStackLayout">
<Grid VerticalOptions="CenterAndExpand" Margin="20" RowSpacing="20">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Entry Placeholder="Eg. Eggs" x:Name="EntryTag" Grid.Row="0"/>
</Grid>
</StackLayout>
<Button Text="Add Ingredient" Grid.Row="1" Clicked="Button_Clicked"/>
<Button Text="Relete Ingredient" Grid.Row="1" Clicked="Button_Clicked_Remove"/>
<CheckBox />
</StackLayout>
</ScrollView>
</Grid>
Note:
Make sure to add a null judgement, or the app may crash:
if (element!=null) {
EntriesStackLayout.Children.Remove(element);
}
To remove an element from a layout
sl.Children.Remove(element);
If you don’t already have a reference to the element
var element = sl.Children.LastOrDefault();
I'm having an issue figuring out how to remove an item from my project while using the same button as I use to perform another task. To sum it up, I'm working on a project where I have a bunch of events a user can like/dislike. What I'm having issues with is trying to figure out how to remove the event from my project once the user has liked the event using the 'like' button. Essentially I want the 'like' button to perform 2 things, one being when its pressed setting it to "true" which is already doing that, but also I want it to remove the event from screen once it's liked.
Here is my XAML:
<StackLayout VerticalOptions="FillAndExpand">
<Grid RowSpacing="0">
<Grid.RowDefinitions>
<RowDefinition Height="1*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Image x:Name="LblEventImage"
Aspect="Fill"
HeightRequest="350" />
<BoxView BackgroundColor="Black"
HeightRequest="350"
Opacity="0.3" />
<Image Source="BackIconOrg.png"
Margin="5,40,0,0"
HorizontalOptions="Start"
VerticalOptions="Start"
Grid.Row="0">
<Image.GestureRecognizers>
<TapGestureRecognizer x:Name="ImgBack" Tapped="backButton_Clicked"/>
</Image.GestureRecognizers>
</Image>
</Grid>
<Frame VerticalOptions="FillAndExpand"
IsClippedToBounds="False"
BackgroundColor="#263A4F"
Margin="0,-40,0,0"
CornerRadius="25"
HasShadow="False">
<StackLayout Margin="0,-50,0,0">
<Grid HeightRequest="200"
VerticalOptions="Start">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="4*" />
<ColumnDefinition Width="6*"/>
</Grid.ColumnDefinitions>
<StackLayout Grid.Column="0"
Padding="5"
Spacing="5"
Margin="0,40,0,0">
<Label x:Name="LblEventName"
TextColor="#fc4600"
FontSize="Large"
FontFamily="TTBold"
FontAttributes="Bold"/>
<StackLayout Orientation="Horizontal"
Spacing="0">
<Frame BackgroundColor="#8B93A6"
BorderColor="#8B93A6"
Padding="8"
CornerRadius="15">
<Label TextColor="White"
x:Name="LblEventCategory"
FontFamily="TTNorms"/>
</Frame>
</StackLayout>
<StackLayout Orientation="Vertical" Grid.ColumnSpan="3">
<Label x:Name="LblEventCity"
TextColor="White"
FontFamily="TTNorms"/>
<Label x:Name="LblEventState"
TextColor="White"
FontFamily="TTNorms"/>
</StackLayout>
<!--<Label x:Name="LblLanguage"
TextColor="White" />
<Label x:Name="LblDuration"
TextColor="White" />-->
</StackLayout>
</Grid>
<Label Text="Details:"
FontSize="Medium"
Margin="0,20,0,0"
TextColor="White"
FontFamily="TTNorms"/>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.65*" />
<ColumnDefinition Width="0.35*" />
</Grid.ColumnDefinitions>
<Label Text="Scheduled Date:"
TextColor="White"
Grid.Row="0"
Grid.Column="0"
FontFamily="TTNorms"/>
<Label Text="August 20, 2021"
TextColor="#8B93A6"
Grid.Row="1"
Grid.Column="0"
FontFamily="TTNorms"/>
<Label Text="Group Size:"
TextColor="White"
Grid.Row="0"
Grid.Column="1"
FontFamily="TTNorms"/>
<Label x:Name="LblEventGroupSize"
TextColor="#8B93A6"
Grid.Row="1"
Grid.Column="1"
FontFamily="TTNorms"/>
<Label Text="Paid:"
TextColor="White"
Grid.Row="2"
Grid.Column="0"
FontFamily="TTNorms"/>
<Label x:Name="LblEventPay"
TextColor="#8B93A6"
Grid.Row="3"
Grid.Column="0"
FontFamily="TTNorms"/>
</Grid>
<BoxView BackgroundColor="#8B93A6"
HeightRequest="1" />
<Label Text="Description"
TextColor="White"
FontFamily="TTNorms"/>
<Label x:Name="LblEventDescription"
TextColor="#8B93A6"
FontFamily="TTNorms"/>
<StackLayout Orientation="Horizontal"
HorizontalOptions="Center"
VerticalOptions="Center"
Spacing="60"
Margin="0,30,0,0">
<Image Source="LikeButton.png"
HeightRequest="150">
<Image.GestureRecognizers>
<TapGestureRecognizer x:Name="likedevent" Tapped="likeButton_Clicked" />
</Image.GestureRecognizers>
</Image>
<Image Source="DislikeButton.png"
HeightRequest="150">
<Image.GestureRecognizers>
<TapGestureRecognizer x:Name="dislikeevent" Tapped="dislikeevent_Tapped"/>
</Image.GestureRecognizers>
</Image>
</StackLayout>
</StackLayout>
</Frame>
</StackLayout>
</ContentPage.Content>
CS:
public partial class MatchDetail : ContentPage
{
private Event event1;
public MatchDetail(int eventId)
{
InitializeComponent();
GetEventDetail(eventId);
}
private async void GetEventDetail(int eventId)
{
event1 = await ApiService.GetEventById(eventId);
LblEventName.Text = event1.Name;
LblEventDescription.Text = event1.Description;
LblEventCity.Text = event1.City;
LblEventImage.Source = event1.FullImageUrl;
LblEventCategory.Text = event1.Category;
LblEventState.Text = event1.State;
LblEventGroupSize.Text = event1.GroupSize.ToString();
LblEventPay.Text = event1.PayTrueFalse;
}
private async void likeButton_Clicked(object sender, EventArgs e)
{
var likedEvent = new Result()
{
Name = LblEventName.Text,
UserId = Preferences.Get("userId", 0),
LikeTrueFalse = "True"
};
if (event1.LikeTrueFalse == "True")
{
//RemoveEvent
}
var response = await ApiService.LikedEvents(likedEvent);
if (response)
{
await DisplayAlert("", "Your event has been liked", "Ok");
}
else
{
await DisplayAlert("Oops", "something went wrong", "cancel");
}
}
private void backButton_Clicked(object sender, EventArgs e)
{
Navigation.PopModalAsync();
}
in your main page
MessagingCenter.Subscribe<object, int>(this, "RemoveEvent", (sender,id) =>
{
// do whatever to remove event "id" here
});
then in your detail page, after you have marked it as a favorite
Messaging.Center.Send<object, int>(this, "RemoveEvent", eventId);
I want to place a image in the half of a frame in my app , i am using xamarin forms to do this ,How can I do this
My Xaml
<StackLayout HorizontalOptions = "FillAndExpand" VerticalOptions="StartAndExpand" >
<ListView x:Name="lv_search" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" RowHeight="175" SeparatorColor="White">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<AbsoluteLayout HorizontalOptions = "FillAndExpand" VerticalOptions="StartAndExpand" >
<Frame BackgroundColor = "White" HorizontalOptions="FillAndExpand" VerticalOptions="StartAndExpand" Margin="20,10,0,0"
HeightRequest="75" AbsoluteLayout.LayoutBounds="0.01,0.9,1,1" AbsoluteLayout.LayoutFlags="All">
<Image Source = "img_frm" BackgroundColor="#14559a" AbsoluteLayout.LayoutBounds="0.009,0.9,0.3,0.6" AbsoluteLayout.LayoutFlags="All" />
<StackLayout Orientation = "Horizontal" HorizontalOptions="FillAndExpand" VerticalOptions="CenterAndExpand">
<AbsoluteLayout HorizontalOptions = "StartAndExpand" >
<Image Source="ellipse_1" VerticalOptions="CenterAndExpand" HorizontalOptions="Start" AbsoluteLayout.LayoutFlags="All"
AbsoluteLayout.LayoutBounds="0.01,0.4,1,1" HeightRequest="100" WidthRequest="100" BackgroundColor="White"/>
<Image Source = "{Binding Image}" AbsoluteLayout.LayoutBounds="0.02,0.4,1,1" AbsoluteLayout.LayoutFlags="All"
HorizontalOptions="CenterAndExpand" VerticalOptions="CenterAndExpand" ></Image>
</AbsoluteLayout>
<Label x:Name="lbl_categories" HorizontalOptions="FillAndExpand" VerticalOptions="CenterAndExpand" Margin="10,0,0,0"
TextColor="Black" Text="{Binding Title}" LineBreakMode="WordWrap" HorizontalTextAlignment="Start"
FontSize="Medium" FontAttributes="Bold" AbsoluteLayout.LayoutBounds="0.3,0.3,1,1" AbsoluteLayout.LayoutFlags="All"/>
<Image HorizontalOptions = "EndAndExpand" VerticalOptions="Center" Source="arrow" AbsoluteLayout.LayoutBounds="0.9,0.3,0.3,0.3"
AbsoluteLayout.LayoutFlags="All" />
</StackLayout>
</Frame>
</AbsoluteLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
But it dosen't develop the design what I want.
Actually I want a design like this
But I get the design like this,how to modify the design into the above image
I hate to say this, but for the result you want to achieve, your xaml is a nightmare. Not only because you are having an excessive amount of elements in your visual tree, but also because you are using AbsoluteLayout inside a ListView.
Even though this is technically possible, it will cause your app losing performance, especially if your ListView gets populated with a lot of items.
Second, creating an image for that blue square also is a waste of memory and will cause more performance drops and ultimately probably OutOfMemoryExceptions on Android if your ListView contains many entries.
You could replace this with a custom View inheriting from a box view and using custom renderers for rendering rounded corners.
Also avoid using a StackLayout within a ListView, as it will also cause performance issues, since the StackLayout does a lot of calculations when being layouted.
As Dennis already mentioned, your way to go is using a Grid for layouting with keeping in mind, that all elements added to the grid will overlay each other in the order of how they have been added within your xaml definition.
Especially when using ListViews, try to use as less elements as possible and avoid elements which need a lot of layout passes.
Even though I am not using it in my example, I'd like to add the information, that you can also use negative margin values for advanced element positioning.
Here is a brief example, I hacked together:
<ListView VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand" RowHeight="80">
<ListView.ItemsSource>
<x:Array Type="{x:Type x:String}">
<!-- quick hack to make the list view populate items without having to write model classes -->
<x:String>Entry 1</x:String>
<x:String>Entry 2</x:String>
<x:String>Entry 3</x:String>
<x:String>Entry 4</x:String>
</x:Array>
</ListView.ItemsSource>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" >
<BoxView BackgroundColor="LightGray" Margin="19,9,9,9" />
<Grid Margin="20,10,10,10" BackgroundColor="White">
<Label Text="{Binding .}" VerticalOptions="Center" FontSize="18" Margin="25,0,0,0"/>
<!-- insert icons, labels, etc here -->
</Grid>
<customs:RoundedBoxView BackgroundColor="DarkBlue" CornerRadius="6" WidthRequest="15" VerticalOptions="FillAndExpand" HorizontalOptions="Start" Margin="10,20,0,20" />
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
The RoundedBoxView class looks like this:
public class RoundedBoxView : BoxView
{
readonly BindableProperty CornerRadiusProperty = BindableProperty.Create("CornerRadius", typeof(double), typeof(double), 0.0);
public double CornerRadius
{
get { return (double)GetValue(CornerRadiusProperty); }
set { SetValue(CornerRadiusProperty, value); }
}
}
This would be the custom renderer for android:
[assembly: ExportRenderer(typeof(RoundedBoxView), typeof(RoundedBoxViewRenderer))]
namespace TestApp.Droid
{
public class RoundedBoxViewRenderer : BoxRenderer
{
public RoundedBoxViewRenderer(Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<BoxView> e)
{
base.OnElementChanged(e);
SetWillNotDraw(false);
Invalidate();
}
public override void Draw(Canvas canvas)
{
var box = Element as RoundedBoxView;
var rect = new Rect();
var paint = new Paint()
{
Color = box.BackgroundColor.ToAndroid(),
AntiAlias = true,
};
GetDrawingRect(rect);
var radius = (float)(box.CornerRadius);
canvas.DrawRoundRect(new RectF(rect), radius, radius, paint);
}
}
And for iOS:
[assembly: ExportRenderer(typeof(RoundedBoxView), typeof(RoundedBoxViewRenderer))]
namespace TestApp.iOS
{
public class RoundedBoxViewRenderer: BoxRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<BoxView> e)
{
base.OnElementChanged(e);
if (Element != null)
{
Layer.MasksToBounds = true;
UpdateCornerRadius(e.NewElement as RoundedBoxView);
}
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (e.PropertyName == CircleView.WidthProperty.PropertyName || e.PropertyName == CircleView.HeightProperty.PropertyName)
{
UpdateCornerRadius(Element as RoundedBoxView);
}
}
void UpdateCornerRadius(RoundedBoxView box)
{
Layer.CornerRadius = (nfloat)(box.CornerRadius);
CGRect bounds = new CGRect(0, 0, box.Width, box.Width);
Layer.Bounds = bounds;
Layer.Frame = bounds;
}
}
Which will render like this:
}
You could use Grid instead of AbsoluteLayout.
I didn't test this, but try something like this:
<Grid
HorizontalOptions="FillAndExpand"
VerticalOptions="StartAndExpand">
<Frame
Grid.Row="0"
Grid.Column="0"
BackgroundColor="White"
HorizontalOptions="FillAndExpand"
VerticalOptions="StartAndExpand"
Margin="20,10,0,0"
HeightRequest="75">
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"></ColumnDefinition>
<ColumnDefinition Width="Auto"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="Auto"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Image
Grid.Row="0"
Grid.Column="0"
Source="ellipse_1"
VerticalOptions="CenterAndExpand"
HorizontalOptions="Start"
HeightRequest="100"
WidthRequest="100"
BackgroundColor="White">
</Image>
<Image
Grid.Row="0"
Grid.Column="1"
Source="{Binding Image}"
HorizontalOptions="CenterAndExpand"
VerticalOptions="CenterAndExpand">
</Image>
<Label
Grid.Row="0"
Grid.Column="2"
x:Name="lbl_categories"
HorizontalOptions="FillAndExpand"
VerticalOptions="CenterAndExpand"
Margin="10,0,0,0"
TextColor="Black"
Text="{Binding Title}"
LineBreakMode="WordWrap"
HorizontalTextAlignment="Start"
FontSize="Medium"
FontAttributes="Bold">
</Label>
<Image
Grid.Row="0"
Grid.Column="3"
HorizontalOptions="EndAndExpand"
VerticalOptions="Center"
Source="arrow">
</Image>
</Grid>
</Frame>
<Image
Margin="10,10,0,0"
Grid.Row="0"
Grid.Column="0"
Source="img_frm"
BackgroundColor="#14559a">
</Image>
</Grid>
Because the Image is created after the Frame in your xaml, it overlaps the Frame. You may need to change the margins of the Frame and blue square shaped Image according to your needs.
I am currently working on a Xamarin CrossPlatform project and have implemented a Listview bound to an ObservableCollection. Everything works out fine until I remove an Item from the ListView. The images in the follow up items within the ListView disappear randomly - not all of them and a different amount of them every time. I guess it has something to do with the MemoryStream, but what do I have to change? Here´s the relevant part of my Model that is bound to the ListView:
public string ImageBase64
{
get
{
return imagebase64;
}
set
{
if (imagebase64 != value)
{
imagebase64 = value;
OnPropertyChanged(nameof(ImageBase64));
OnPropertyChanged(nameof(ImageSource));
}
}
}
public ImageSource ImageSource
{
get
{
if (!string.IsNullOrEmpty(imagebase64))
{
return ImageSource.FromStream(() => new MemoryStream(Convert.FromBase64String(imagebase64)));
}
else
{
return null;
}
}
}
Here´s the relevant XAML:
<ListView x:Name="listView" Margin="20" ItemsSource="{Binding}" ItemSelected="OnListItemSelected" HasUnevenRows="True" SeparatorColor="{StaticResource primaryGreen}" SeparatorVisibility="Default">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid Margin="0,5,0,5">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="65" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="45" />
</Grid.ColumnDefinitions>
<Image Grid.Column="0" Grid.RowSpan="3" Margin="-2,-2,-2,-2" Source="{Binding ImageSource}" HorizontalOptions="Start" VerticalOptions="Center" Aspect="AspectFill"/> <!-- This is the displayed Image -->
<Label Margin="10,0,0,0" Grid.Column="1" Grid.Row="0" FontAttributes="Bold" FontSize="18" TextColor="{StaticResource primaryGreen}" Text="{Binding VorNachname}" VerticalTextAlignment="Start" HorizontalTextAlignment="Start"/>
<Label Margin="10,0,0,0" Grid.Column="1" Grid.Row="1" Text="{Binding MediumSelected.Wert, StringFormat='via {0}'}" HorizontalOptions="FillAndExpand" VerticalTextAlignment="Start" HorizontalTextAlignment="Start"/>
<StackLayout Margin="10,0,0,0" Grid.Column="1" Grid.Row="2" Orientation="Horizontal" HorizontalOptions="FillAndExpand">
<Label Text="{Binding Alter,StringFormat='Alter: {0}'}" VerticalTextAlignment="Start" HorizontalTextAlignment="Start" HorizontalOptions="Start"/>
</StackLayout>
<StackLayout Margin="0,0,0,-5" Grid.Column="2" Grid.RowSpan="3" Orientation="Vertical" HorizontalOptions="End" VerticalOptions="End">
<Button WidthRequest="40" HeightRequest="40" BackgroundColor="White" BorderWidth="0" BorderColor="White" Image="socialmedia_18.png" Clicked="OnChangeClicked" CommandParameter ="{Binding}" VerticalOptions="EndAndExpand" />
<Button Margin="0,-15,0,0" WidthRequest="40" HeightRequest="40" BackgroundColor="White" BorderColor="White" Image="cancel_18.png" Clicked="OnDeleteClicked" CommandParameter ="{Binding}" VerticalOptions="End" />
</StackLayout>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
...and the Code behind:
async void OnDeleteClicked(object sender, EventArgs e)
{
Helper.TrackEvent("PeopleList_OnDeleteClicked");
//Get selected Person
Person person = (Person)((Button)sender).CommandParameter;
//Remove from Model
DBHelper.DBModel.People.Remove(person);
//Update database
App.Database.UpdateWithChildren(DBHelper.DBModel);
}
EDIT:
Resizing the images does not help, same problem. I tried it by binding a testvariable ImageSourceThumb to the ListViewItemImage:
public ImageSource ImageSourceThumb
{
get
{
if (!string.IsNullOrEmpty(imagebase64))
{
return ImageSource.FromStream(() => new MemoryStream(ImageResizer.ResizeImage(Convert.FromBase64String(imagebase64), 64, 64)));
}
else
{
return null;
}
}
}
I had a similar problem. When I loaded or updated my listview not all the images showed up.
I fixed my problem resizing the images. Huge images gived me a outofmemory exception. Resizing those images to a smaller resolution fixed these problems.