locked
Image take all available height and then crop width to form square on different resolutions RRS feed

  • Question

  • User386791 posted

    I'm making my app adaptive for different resolutions. I have page divided in 2 halves with Grid.RowDefinition="*", first half is green, second is red. I'm having the problem with red part.

    Big Title (text "Novice") is size "Title" and text in yellow (thumb byte testhh is font size "Small".
    What I want to accomplish is for image to take all available height and set the same width and then either crop image or set Aspect="AspectFill". Right now, image width and height are hardcoded to image (height and width are set to 210, this emulator is of resolution 1080x1920 at 420dpi) Second image is cut off, because it's horizontal collection view, there can be any number of images with text, so it's important for them to be of the same size. How to make this dynamic?

    <Grid Padding="10">
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <StackLayout Grid.Row="0" BackgroundColor="Green">
            <StackLayout Orientation="Horizontal">
                <Label
                    Style="{StaticResource TitleLabel}"
                    Text="{x:Static resources:AppResources.Zahtevki}" />
                <Label
                    HorizontalOptions="EndAndExpand"
                    Style="{StaticResource NearTitlelabel}"
                    Text="{x:Static resources:AppResources.AllTasks}"
                    VerticalOptions="End">
                </Label>
            </StackLayout>
            <CollectionView EmptyView="{x:Static resources:AppResources.NoTasksAvailable}" ItemsSource="{Binding Tasks}">
                <CollectionView.ItemTemplate>
                    <DataTemplate>
                        <ContentView Padding="0,0,0,0" HorizontalOptions="StartAndExpand">
                            <Frame Margin="0,0,0,5" Style="{StaticResource ZahtevkiUnfinishedFrame}">
                                <Grid Grid.Row="0" Style="{StaticResource TaskGrid}">
                                    <Image
                                        Grid.Column="0"
                                        Source="alarm.png"
                                        Style="{StaticResource IconImage}"
                                        VerticalOptions="Center" />
                                    <StackLayout
                                        Grid.Column="1"
                                        Spacing="0"
                                        VerticalOptions="Center">
                                        <Label
                                            LineBreakMode="TailTruncation"
                                            Style="{StaticResource ZahtevkiTopLabel}"
                                            Text="{Binding Title}" />
                                        <Label Style="{StaticResource ZahtevkiBottomLabel}" Text="{Binding Date, StringFormat='{0:dd.MM.yyyy}'}" />
                                    </StackLayout>
                                </Grid>
                            </Frame>
                        </ContentView>
                    </DataTemplate>
                </CollectionView.ItemTemplate>
            </CollectionView>
        </StackLayout>
        <StackLayout Grid.Row="1" BackgroundColor="Red">
            <StackLayout Orientation="Horizontal">
                <Label
                    Margin="5,0,0,0"
                    Style="{StaticResource TitleLabel}"
                    Text="{x:Static resources:AppResources.Novice}" />
                <Label
                    HorizontalOptions="EndAndExpand"
                    Style="{StaticResource NearTitlelabel}"
                    Text="{x:Static resources:AppResources.AllNews}"
                    VerticalOptions="End">
                </Label>
            </StackLayout>
            <CollectionView
                EmptyView="{x:Static resources:AppResources.NoNewsAvailable}"
                IsVisible="{Binding IsBusy, Converter={StaticResource NegateBoolConverter}}"
                ItemsLayout="HorizontalList"
                ItemsSource="{Binding NewsList}">
                <CollectionView.ItemTemplate>
                    <DataTemplate>
                        <ContentView Padding="0,0,5,0">
                            <StackLayout BackgroundColor="Yellow">
                                <forms:CachedImage
                                    Aspect="AspectFill"
                                    DownsampleToViewSize="True"
                                    HeightRequest="210"
                                    Source="{Binding files[0].Image, Converter={StaticResource Base64ToImageConverter}}"
                                    WidthRequest="210" />
                                <Label
                                    FontSize="Small"
                                    LineBreakMode="TailTruncation"
                                    Text="{Binding Title}"
                                    TextColor="Black" />
                            </StackLayout>
                        </ContentView>
                    </DataTemplate>
                </CollectionView.ItemTemplate>
            </CollectionView>
        </StackLayout>
    </Grid>
    

    Thank you all! :)

    Sunday, October 27, 2019 5:28 PM

Answers

  • User369979 posted

    You need to bind your item's width to the collection view's width and then convert it to the half value. The second collection view's template could be like:

    <CollectionView.ItemTemplate>
        <DataTemplate>
            <ContentView Padding="0,0,5,0">
                <StackLayout BackgroundColor="Yellow">
                    <forms:CachedImage
                    Aspect="AspectFill"
                    Source="{Binding files[0].Image, Converter={StaticResource Base64ToImageConverter}}"
                    HorizontalOptions="StartAndExpand"
                    VerticalOptions="FillAndExpand"
                    WidthRequest="{Binding Width, Source={x:Reference mCollectionView}, Converter={StaticResource ToPercentWidthConverter}}" />
                    <Label
                    FontSize="Small"
                    LineBreakMode="TailTruncation"
                    Text="{Binding Title}"
                    TextColor="Black" />
                </StackLayout>
            </ContentView>
        </DataTemplate>
    </CollectionView.ItemTemplate>
    

    And then use converter to modify the multiplier:

    public class ToPercentWidthConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            double parentWidth = (double)value;
    
            return (parentWidth-5)/2;
        }
    
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
    

    The constant 5 depends on the padding you set to the ContentView.

    • Marked as answer by Anonymous Thursday, June 3, 2021 12:00 AM
    Monday, October 28, 2019 9:07 AM

All replies

  • User369979 posted

    You need to bind your item's width to the collection view's width and then convert it to the half value. The second collection view's template could be like:

    <CollectionView.ItemTemplate>
        <DataTemplate>
            <ContentView Padding="0,0,5,0">
                <StackLayout BackgroundColor="Yellow">
                    <forms:CachedImage
                    Aspect="AspectFill"
                    Source="{Binding files[0].Image, Converter={StaticResource Base64ToImageConverter}}"
                    HorizontalOptions="StartAndExpand"
                    VerticalOptions="FillAndExpand"
                    WidthRequest="{Binding Width, Source={x:Reference mCollectionView}, Converter={StaticResource ToPercentWidthConverter}}" />
                    <Label
                    FontSize="Small"
                    LineBreakMode="TailTruncation"
                    Text="{Binding Title}"
                    TextColor="Black" />
                </StackLayout>
            </ContentView>
        </DataTemplate>
    </CollectionView.ItemTemplate>
    

    And then use converter to modify the multiplier:

    public class ToPercentWidthConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            double parentWidth = (double)value;
    
            return (parentWidth-5)/2;
        }
    
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
    

    The constant 5 depends on the padding you set to the ContentView.

    • Marked as answer by Anonymous Thursday, June 3, 2021 12:00 AM
    Monday, October 28, 2019 9:07 AM
  • User386791 posted

    @LandLu said: You need to bind your item's width to the collection view's width and then convert it to the half value. The second collection view's template could be like:

    <CollectionView.ItemTemplate>
        <DataTemplate>
            <ContentView Padding="0,0,5,0">
                <StackLayout BackgroundColor="Yellow">
                    <forms:CachedImage
                    Aspect="AspectFill"
                    Source="{Binding files[0].Image, Converter={StaticResource Base64ToImageConverter}}"
                    HorizontalOptions="StartAndExpand"
                    VerticalOptions="FillAndExpand"
                    WidthRequest="{Binding Width, Source={x:Reference mCollectionView}, Converter={StaticResource ToPercentWidthConverter}}" />
                    <Label
                    FontSize="Small"
                    LineBreakMode="TailTruncation"
                    Text="{Binding Title}"
                    TextColor="Black" />
                </StackLayout>
            </ContentView>
        </DataTemplate>
    </CollectionView.ItemTemplate>
    

    And then use converter to modify the multiplier:

    public class ToPercentWidthConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            double parentWidth = (double)value;
    
            return (parentWidth-5)/2;
        }
    
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
    

    The constant 5 depends on the padding you set to the ContentView.

    Thank you!

    I modified it a bit, to make it square, I set width and height to this converter

    <forms:CachedImage
        Aspect="AspectFill"
        DownsampleToViewSize="True"
        HeightRequest="{Binding Height, Source={x:Reference mCollectionView}, Converter={StaticResource ToPercentWidthConverter}}"
        Source="{Binding files[0].Image, Converter={StaticResource Base64ToImageConverter}}"
        WidthRequest="{Binding Height, Source={x:Reference mCollectionView}, Converter={StaticResource ToPercentWidthConverter}}" />
    

    And in Converter I substract padding from grid and padding from label under image

     public class ToPercentWidthConverter : IValueConverter
        {
            public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
            {
                if (value == null)
                    return null;
    
                double parentWidth = (double)value;
                return parentWidth - Device.GetNamedSize(NamedSize.Small, typeof(Label)) - 5 - 10;
            }
    
            public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
            {
                throw new NotImplementedException();
            }
        }
    
    Tuesday, October 29, 2019 11:36 AM
  • User369979 posted

    If you feel this issue has been solved please mark the helpful answer.

    Wednesday, October 30, 2019 2:15 AM