I have a Xaml page with a grid with relative heights
<RowDefinition Height="1*">
<RowDefinition Height="2*">
<RowDefinition Height="3*">
Now on the middle row (And i don't know it's exact height since it scales with the display size) I want to have a circular image. Since I have not set a heightrequest / widthrequest for the image I think I need to bind it to actual height.
I tried a lot of things resulting in my 'latest effort which is the following code but still does not give the desired result
<!-- try 1 -->
<yummy:PancakeView BackgroundColor="Aqua" CornerRadius="{Binding Source={RelativeSource Self}, Path=ActualHeight, Converter={converters:PercentageConverter}, ConverterParameter='0,5'}" IsClippedToBounds="True" BorderColor="Black" BorderThickness="4">
<Image Source="{Binding NarrationImage}" ></Image>
</yummy:PancakeView>
<!-- try 2 -->
<Grid x:Name="RefGrid" WidthRequest="1"></Grid>
<Frame
HeightRequest="{Binding Path=ActualHeight, Source={x:Reference RefGrid}}"
WidthRequest="{Binding Path=ActualHeight, Source={x:Reference RefGrid}}"
CornerRadius="{Binding Path=ActualHeight, Source={x:Reference RefGrid}}"
IsClippedToBounds="True" Padding="0" VerticalOptions="CenterAndExpand">
<Image Source="{Binding NarrationImage}" Aspect="AspectFill"></Image>
</Frame>
Since you had set the Height of Row as * . The real size of Frame in runtime depend on the size of Grid . In your case , the Height of Frame equals 1/3 of the Grid and the Width equals the width of the Grid .
If you want to get the value of them .You could create a custom Frame .And rewrite the method OnSizeAllocated
using Xamarin.Forms;
namespace App10
{
public class MyFrame:Frame
{
protected override void OnSizeAllocated(double width, double height)
{
if(width>0&&height>0)
{
var size =width<height ? width: height ;
CornerRadius = (float)size / 2;
}
base.OnSizeAllocated(width, height);
}
public MyFrame()
{
SizeChanged += MyFrame_SizeChanged;
}
private void MyFrame_SizeChanged(object sender, EventArgs e)
{
var width = this.Width;
var height = this.Height;
if (width > 0 && height > 0)
{
var size = width < height ? width : height;
CornerRadius = (float)size / 2;
}
}
}
}
This method will been invoked multi times when it been first added to the parent view. The last time it will return the current size . You can do something you want .
Related
I want to resize webview with window.
But, when I reduce the size of the window, the webview is cut off.
(When I grow the size of the window it looks normal.)
<Grid>
<WebView x:Name="m_WebView" HorizontalAlignment="Left" Height="350" Margin="0,0,0,0" VerticalAlignment="Top" Width="568" ScriptNotify="m_WebView_ScriptNotify" NavigationCompleted="m_WebView_OnNavigationCompleted" x:FieldModifier="public"/>
<ProgressRing x:Name="workingProgressRing" HorizontalAlignment="Center" VerticalAlignment="Center" Width="50" Height="50"/>
</Grid>
private void Page_onSizeChanged2(object sender, SizeChangedEventArgs e)
{
double widthRatio = e.NewSize.Width / (double)568;
double heightRatio = e.NewSize.Height / (double)320;
double newRatio = widthRatio < heightRatio ? widthRatio : heightRatio;
double newWidth = 568 * newRatio;
double newHeight = 320 * newRatio;
m_WebView.RenderTransform = new CompositeTransform { ScaleX = newRatio, ScaleY = newRatio };
((CompositeTransform)m_WebView.RenderTransform).TranslateX = -(newWidth - 568 * widthRatio) / 2;
((CompositeTransform)m_WebView.RenderTransform).TranslateY = -(newHeight - 320 * heightRatio) / 2;
}
Normal window picture.
Cut off webview picture.
The proper way to size controls in UWP is scaling the automatically based on the layout instead of directly hardcoding Width and Height values.
In your case you could remove the Width and Height attributes, set HorizontalAlignment and VerticalAlignment to Stretch and let the WebView scale with the Grid instead.
Current:
Goal:
Attempting to implement a WrapLayout to allow for dynamic button addition in a clean horizontally adding format, as shown in the 'Goal' picture. However as seen in 'Current', the sizing of the buttons in the WrapLayout are far from ideal.
Have found through simple trial and error that using height and width requests in any of the elements (scrollView, wrapLayout, buttons) result in no change to the button formats.
HeightRequest = xx;
WidthRequest = xx;
The only way, I've found thus far, to change the sizing of the wrapLayout elements is to add a large amount of children, example:
As displayed, my understanding of how to format WrapLayout children is rather lacking. So, how to format the number of children allowed on each row and how to properly format the children of a WrapLayout?
Current implementation developed following the WrapLayout class shown in the Xamarin Developer Sample for WrapLayout
ScrollView scrollView = new ScrollView {
Margin = new Thickness(20, 20, 20, 20),
};
WrapLayout wrapLayout;
wrapLayout = new WrapLayout {
ColumnSpacing = 12,
};
scrollView.Content = wrapLayout;
wrapLayout.Children.Add(
new Button
{
Text = "9 ° (?)",
BackgroundColor = Color.Yellow,
BorderColor = Color.Black,
}
);
wrapLayout.Children.Add(
new Button
{
Text = "10.5 ° (?)",
BackgroundColor = Color.Gray,
BorderColor = Color.Black,
}
);
You should look at CollectionView Nuget Package
You can use the GridCollectionView, which is based on the WrapLayout.
There, you can either use:
UniformGrid
The number of columns arranged in each row is specified. Each column width becomes the width obtained by dividing the row width by that value. This number of columns can be set by PortraitColumns and LandscapeColumns properties.
"
AutoSpacingGrid
Once a column width is specified, each column is arranged until fitting in each row and adjusted automatically each spacing. A column width can be set by ColumnWidth property and Setting SpacingType property can change how to adjust the spacing.
An Example:
<ai:GridCollectionView
ItemsSource="{Binding ItemsSource}" TouchFeedbackColor="Yellow"
ColumnWidth="100" ColumnHeight="1.0" >
<ListView.ItemTemplate>
<DataTemplate>
<ai:ContentCell>
<Label Text="{Binding Name}" />
</ai:ContentCell>
</DataTemplate>
</ListView.ItemTemplate>
</ai:GridCollectionView>
I recommend using the AiForms.Layout package:
https://dev.to/muak_x/wraplayout-and-repeatablestacklayout-for-xamarinforms-1dck
here is the sample, and it works as we expected:
<aiforms:WrapLayout Spacing="4" UniformColumns="3" IsSquare="true" HorizontalOptions="FillAndExpand">
<BoxView Color="Red" />
<BoxView Color="Blue" />
<BoxView Color="Green" />
<BoxView Color="Black" />
<BoxView Color="Yellow" />
</aiforms:WrapLayout>
And there is a RepeatableWrapLayout with Itemtemplate and ItemsSource Binding.
How can I set the size of the image inside of a list view. Currently I have several lists that have icons but I don't see any options for changing the aspect ratio or size of the image so it just gets blown up to the height of the list item.
all the images are from the Drawable folder
var cell = new DataTemplate(typeof(MenuTextCell));
cell.SetBinding(TextCell.TextProperty, "Title");
cell.SetBinding(ImageCell.ImageSourceProperty, "IconSource");
cell.SetValue(BackgroundColorProperty, Color.Transparent);
cell.SetValue(TextCell.TextColorProperty, Color.FromHex("262626"));
I am using a custom renderer
public class MenuTextCellRenderer : ImageCellRenderer
{
protected override View GetCellCore (Cell item, View convertView, ViewGroup parent, Context context)
{
var cell = (LinearLayout)base.GetCellCore (item, convertView, parent, context);
cell.SetPadding(20, 10, 0, 10);
cell.DividerPadding = 50;
var div = new ShapeDrawable();
div.SetIntrinsicHeight(1);
div.Paint.Set(new Paint { Color = Color.FromHex("b7b7b7").ToAndroid() });
if (parent is ListView)
{
((ListView)parent).Divider = div;
((ListView)parent).DividerHeight = 1;
}
var icon = (ImageView)cell.GetChildAt(0);
var label = (TextView)((LinearLayout)cell.GetChildAt(1)).GetChildAt(0);
label.SetTextColor(Color.FromHex("262626").ToAndroid());
label.TextSize = Font.SystemFontOfSize(NamedSize.Large).ToScaledPixel();
label.TextAlignment = TextAlignment.Center;
label.Text = label.Text.ToUpper();
var secondaryLabel = (TextView)((LinearLayout)cell.GetChildAt(1)).GetChildAt(1);
secondaryLabel.SetTextColor(Color.FromHex("262626").ToAndroid());
secondaryLabel.TextSize = Font.SystemFontOfSize(NamedSize.Large).ToScaledPixel();
label.TextAlignment = TextAlignment.Center;
return cell;
}
You are now dealing with an Android ImageView.
You have your reference via var icon = (ImageView)cell.GetChildAt(0).
You can now customize it via methods such as .setScaleType() for aspect ratio related, and use .layout() to change the position / size.
Try something like this on your ListView.ItemTemplate, instead of using the imagecell. You can also write your custom cell.
<DataTemplate>
<ViewCell>
<StackLayout VerticalOptions="FillAndExpand" Orientation="Horizontal" Padding="10">
<Image Aspect="AspectFill" HeightRequest ="20" WidthRequest="20" Source="{Binding IconSource}" />
<Label Text="{Binding Title}" YAlign="Center" Font="Medium" />
</StackLayout>
</ViewCell>
I have put an image in the scrollview and canvas as xaml below:
<ScrollViewer x:Name="scroll" HorizontalAlignment="Center" VerticalAlignment="Center" Width="340" Height="480">
<Canvas x:Name="canvas" HorizontalAlignment="Center" VerticalAlignment="Center" Width="340" Height="480" Background="Blue">
<Image x:Name="photo" Stretch="Fill" HorizontalAlignment="Center" VerticalAlignment="Center" ManipulationMode="All" Width="340" Height="480">
<Image.RenderTransform>
<CompositeTransform/>
</Image.RenderTransform>
</Image>
</Canvas>
</ScrollViewer>
After that, I created a button to load and crop the image:
private async void btnCrop_Click(object sender, RoutedEventArgs e)
{
FileOpenPicker fileOpenPicker = new FileOpenPicker();
fileOpenPicker.ViewMode = PickerViewMode.Thumbnail;
fileOpenPicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
fileOpenPicker.FileTypeFilter.Add(".jpg");
fileOpenPicker.FileTypeFilter.Add(".jpeg");
fileOpenPicker.FileTypeFilter.Add(".png");
fileOpenPicker.FileTypeFilter.Add(".bmp");
file = await fileOpenPicker.PickSingleFileAsync();
if (file != null)
{
var fileStream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read);
BitmapDecoder decoder = await BitmapDecoder.CreateAsync(fileStream);
BitmapTransform transform = new BitmapTransform();
BitmapBounds bounds = new BitmapBounds();
bounds.X = bounds.Y = 0;
bounds.Height = bounds.Width = 150;
transform.Bounds = bounds;
PixelDataProvider pix = await decoder.GetPixelDataAsync(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Straight, transform, ExifOrientationMode.RespectExifOrientation, ColorManagementMode.ColorManageToSRgb);
byte[] pixels = pix.DetachPixelData();
WriteableBitmap cropBmp = new WriteableBitmap(340, 480);
Stream pixStream = cropBmp.PixelBuffer.AsStream();
pixStream.Write(pixels, 0, 150 * 150 * 4);
photo.Source = cropBmp;
}
}
The image has been crop and displayed successful. But when I zoom my image, I just want crop the image within the canvas instead of hard code. The code above is hard code the BitmapBounds width and height. How do I solve it? Thanks
I have an image placed on a Page as follow
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Image Name="im" Source="/images/hqdefault.jpg" Height="250" Stretch="UniformToFill" VerticalAlignment="Center"/>
</Grid>
this is the whole page XAML, image can be downloaded from http://i.ytimg.com/vi/wNKKCHv-oOw/hqdefault.jpg
Code behind contains some logic to handle the PageOrientation_Change
private void PhoneApplicationPage_OrientationChanged(object sender, OrientationChangedEventArgs e)
{
if (Orientation == PageOrientation.Landscape ||
Orientation == PageOrientation.LandscapeLeft ||
Orientation == PageOrientation.LandscapeRight)
{
im.Height = Application.Current.Host.Content.ActualWidth;
im.Width = Application.Current.Host.Content.ActualHeight;
im.VerticalAlignment = System.Windows.VerticalAlignment.Bottom;
im.HorizontalAlignment = System.Windows.HorizontalAlignment.Right;
}
else
{
im.Height = 250;
im.Width = Application.Current.Host.Content.ActualWidth;
}
}
If some one may try this he/she may find that StrechToFill crops the content of the image from bottom where as I am expecting it to crop it from top and bottom equally and keep the image content centered within image control.
HOpe I have made myself clear if not please consider making a sample from provided code. Thanks a lot.
Main problem was the setting of height or width on the Image control, i am now well aware not to give heigh or width on the image control nor on media element. if you need a a fixed height for example in portrait mode you may put it in a grid control and set its height or width. following is the code which worked for me.
<Grid Name="grdMedia"
Grid.Row="1"
VerticalAlignment="Stretch"
HorizontalAlignment="Stretch"
Height="250">
<Image Name="imThumbnail"
Grid.Row="1"
Stretch="UniformToFill"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>
</Grid>
And following code if you want to change this picture to full screen in landscape mode
private void SetUIInLandscape()
{
SystemTray.IsVisible = false;
//Do not change the height or width of image control nor its alignments
//Hide every thing else
grdMedia.Height = Application.Current.Host.Content.ActualWidth;
grdMedia.Width = Application.Current.Host.Content.ActualHeight;
}
private void SetUIInPortrait()
{
SystemTray.IsVisible = true;
//Do not change the height or width of image control nor its alignments
//Make every thing else visible
grdMedia.Height = 250;
grdMedia.Width = Application.Current.Host.Content.ActualWidth;
}
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Image Name="im" Source="/images/hqdefault.jpg" Height="Auto" HorizontalAlignment="Stretch" VerticalAlignment="Center"/>
</Grid>
try this then the u need not do anything in PhoneApplicationPage_OrientationChanged event.