I have a Xamarin.Forms page written in .xaml On iOS platform only I am trying to wrap the content of the page in ScrollView to help fix resizing issue when keyboard is shown.
The page looks something like this:
<base:mypagebase...>
<ContentPage.Resources>
...
</ContentPage.Resources>
<ContentPage.Content>
<RelativeLayout x:Name="ViewContentLayout" VerticalOptions="FillAndExpand">
....
</RelativeLayou>
</ContentPage.Content>
</base:mypagebase>
I am trying in the constructor of my mpage.xaml.cs after InitializeComponent() to wrap my RelativeLayout in ScrollView
Something like this:
if (Device.RuntimePlatform == Device.iOS)
{
var scroll = new ScrollView();
scroll.Orientation = ScrollOrientation.Vertical;
scroll.VerticalOptions = LayoutOptions.FillAndExpand;
scroll.Content = ViewContentLayout;
Content = scroll;
}
It passes through but throws exception later:
Object reference not set to an instance of an object
at Xamarin.Forms.RelativeLayout.OnSizeRequest (System.Double widthConstraint, System.Double heightConstraint) [0x00017] in RelativeLayout.cs:185
The order in which the properties are called matters, seems like the Content root had to be set first:
if (Device.RuntimePlatform == Device.iOS)
{
var viewContentLayout = ViewContentLayout;
var scroll = new ScrollView();
Content = scroll;
scroll.Content = viewContentLayout;
}
Related
Entry box should be rounded with an icon to the left or right in it. I'm using the code presented here to create this custom entry.
1. Remove the rectangular border of Entry
Used CustomRender to achieve this.
Forms
public class NoUnderlineEntry : Entry
{
public NoUnderlineEntry()
{
}
}
Android
Set Background to null
public class NoUnderLineEntryRenderer : EntryRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);
this.Control.Background = null;
}
}
iOS
Set BorderStyle to None
public class NoUnderlineEntryRenderer : EntryRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);
this.Control.BorderStyle = UIKit.UITextBorderStyle.None;
}
}
2. Placing Image next to Entry
Adding Image and Entry to the same Grid in two columns.
3. Adding Rounded border to the Entry and Image
Add them inside a Frame with CornerRadius.
XAML
<StackLayout>
<Frame
Padding="10, 5, 10, 5"
HasShadow="False"
BorderColor="Gray"
CornerRadius="30">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="50"/>
</Grid.ColumnDefinitions>
<local:NoUnderlineEntry/>
<Image Source="icon.png" Grid.Column="1" WidthRequest="50" Aspect="AspectFit"/>
</Grid>
</Frame>
</StackLayout>
UI result:
Please note: I won't present a copy-and-paste-able answer, but rather an outline on how to add the images. You'll have to integrate the code in your solution by yourself.
On iOS
There already is an answered question on how to achieve this with Swift on iOS, you can find it here.
Basically what to do is to set the right view (or left view respectively) on the UITextField from your custom renderer (in OnElementChanged).
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);
var imageView = new UIImageView(new CGRect(0, 0, 20, 20));
var image = UIImage.FromFile("ic_location.png");
imageView.Image = image;
this.Control.RightView = imageView;
this.Control.RightViewMode = UITextFieldViewMode.Always;
}
This sets the view in the right of the UITextField to a UIImageView. If you wanted to show the icon before the text instead, you'd have to set LeftView and LeftViewMode instead. This is how it looks like. (I intentionally did not inline the image, because it rendered the answer less redable.)
Of course the file ic_location.png has to be in your platform projects resources.
You may need some fine tuning, but basically that's it.
On Android
The TextView.setCompoundDrawablesWithIntrinsicBounds
Sets the Drawables (if any) to appear to the left of, above, to the right of, and below the text. Use null if you do not want a Drawable there. The Drawables' bounds will be set to their intrinsic bounds. (source)
By loading the icon from the resource and setting it with SetCompoundDrawablesWithIntrinsicBounds (uppercase now, since we're now on C#) you can display the Entry with the icon:
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);
this.Control.SetCompoundDrawablesWithIntrinsicBounds(null, null, this.GetIcon(), null);
this.Control.CompoundDrawablePadding = 25;
}
private Drawable GetIcon()
{
int resID = Resources.GetIdentifier("ic_location", "drawable", this.Context.PackageName);
var drawable = ContextCompat.GetDrawable(this.Context, resID);
var bitmap = ((BitmapDrawable)drawable).Bitmap;
return new BitmapDrawable(Resources, Bitmap.CreateScaledBitmap(bitmap, 20, 20, true));
}
This is how the Android version looks like.
For showing the icon on left left, pass the drawable to the first parameter instead of the third.
I have two images to simulate the click on the button, but I want is when clicking the image and change call another screen. And the process does not happen because the application is stopping
<StackLayout>
<!-- Place new controls here -->
<Image Source="botaocadastrolivre.png">
<Image.GestureRecognizers>
<TapGestureRecognizer
Tapped="OnTapGestureRecognizerTapped"
NumberOfTapsRequired="1" />
</Image.GestureRecognizers>
</Image>
</StackLayout>
void OnTapGestureRecognizerTapped(object sender, EventArgs args)
{
tapCount++;
var imageSender = (Image)sender;
// watch the monkey go from color to black&white!
if (tapCount % 2 == 0)
{
imageSender.Source = "botaocadastrolivre.png";
}
else
{
imageSender.Source = "botaocadastroPresed.png";
Navigation.PushAsync(new Nova());
}
// Task.Delay(100)
//Navigation.PushAsync(new Nova());
}
Go to your App.xaml.cs file, find the line that says something like:
MainPage = new MainPage();
and change it into:
MainPage = new NavigationPage(new MainPage());
This will wrap your page into a navigation page and then the Navigation object will know how to navigate from one page to the other.
It might be wise to read up on navigation concepts in Xamarin.Forms: https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/navigation/
I have tried to set the width and also min height and min width but still the dialogue wont change to full screen. tried window.bounds too but teh dialog wont expand beyond a fixed width.
public sealed partial class ContentDialog1 : ContentDialog
{
public ContentDialog1()
{
this.InitializeComponent();
this.MinWidth = Window.Current.Bounds.Width;
}
private void ContentDialog_PrimaryButtonClick(ContentDialog sender, ContentDialogButtonClickEventArgs args)
{
}
private void ContentDialog_SecondaryButtonClick(ContentDialog sender, ContentDialogButtonClickEventArgs args)
{
}
}
}
<ContentDialog
x:Class="PowerUp.UWP.View.ContentDialog1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:PowerUp.UWP.View"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="TITLE"
PrimaryButtonText="Button1"
SecondaryButtonText="Button2"
PrimaryButtonClick="ContentDialog_PrimaryButtonClick"
SecondaryButtonClick="ContentDialog_SecondaryButtonClick"
MinWidth ="2000">
<Grid x:Name="cd1" >
</Grid>
This is what I want
This is how content dialog is shown in my application
It is actually very simple, did a bit research and found the simplest answer, you can keep doing what you were already doing in the first place and just set the FullSizeDesired property of your ContentDialog to true.
Popup
Or you can try it with popup.
var c = Window.Current.Bounds;
var okButton=new Button{Content="Ok"};
okButton.Click += okButtonClicked; // now where you have this okButtonClicked event you can execute any code you want including, closing the popup.
var g = new Grid
{
Width = c.Width,
Height = c.Height,
Background = new SolidColorBrush(Color.FromArgb(0x20, 0, 0, 0)),
Children =
{
new StackPanel
{
Width = 400,
Height = 200,
Background = new SolidColorBrush(Colors.White),
Children=
{
new TextBlock{Text="Title"},
new TextBlocl{Text="description"},
okButton
}
}
}
};
var p = new Popup
{
HorizontalOffset = 0,
VerticalOffset = 0,
Width = c.Width,
Height = c.Height,
Child = g
};
p.IsOpen = true; // open when ready
Notice that Child of popup is g which is a grid, you can put your content within this grid or you can use a StackPanel instead of this grid and then put your contents within that StackPanel, whatever you want to do here is your decision, putting elements in popup is exactly like putting elements in a ContentDialog.
Achieving the same with a simple Grid alongside your frame
<Grid>
<Grid Horizontallignment="Stretch" VerticalAlignment="Stretch" Visibility="Collapsed" x:Name="ContentGrid" canvas.ZIndex="5"><--this grid will act as content dialog, just toggle its visibility to the backend-->
<--put all your content here along with your ok and cancel buttons-->
</Grid>
<Frame/> <--this is the code where you have your frame-->
</Grid>
in above code the frame and your actually content grid will be parallel to each other, and whenever content grid is visible only it will be shown in the app because it has ZIndex greater than 0 and your frame will hide behind it, and whenever its visibility is collapsed it will not be shown and you will be able to see your frame normally.
I'm extending a control to be able to reuse it across my current Xamarin project. As part of this control, I need to create a DataTemplate programmatically. I have this part figured out and it works ok.
The DataTemplate has a Label in it. I need to bind the Label's BindingContext property to {Binding Source}. I need to bind the Label's Text property to {Binding Path=Name}.
This works in XAML, but I don't want to have to copy it to a million different places in the code base.
<dxGrid:TemplateColumn FieldName="MyPropertyName"
Caption="MyColumn">
<dxGrid:TemplateColumn.DisplayTemplate>
<DataTemplate>
<Label BindingContext="{Binding Source}"
Text="{Binding Source, Path=MyPropertyName}" />
</DataTemplate>
</dxGrid:TemplateColumn.DisplayTemplate>
My extended control looks like this right now:
public class MyColumn : TemplateColumn
{
public MyColumn()
{
DataTemplate displayTemplate = new DataTemplate(() =>
{
BindingBase textBinding = new Binding(FieldName);
Label label = new Label();
// TODO: Bind BindingContextProperty to {Binding Source}
//label.SetBinding(BindingContextProperty, binding);
label.SetBinding(Label.TextProperty, textBinding);
return new ViewCell
{
View = label
};
});
DisplayTemplate = displayTemplate;
}
}
I'm getting hung up in the binding because I'm not sure how to do the equivalent of {Binding Source} in code. Any help would be appreciated.
#Eugene - Thanks for the response. Unfortunately this does not work and binding to "Source" like that throws a Null Reference Exception. I made another pass at it this morning and got it working this way:
public MyColumn()
{
DataTemplate displayTemplate = new DataTemplate(() =>
{
Grid grid = new Grid();
grid.SetBinding(Grid.BindingContextProperty, "Source");
Label label = new Label();
label.SetBinding(Label.TextProperty,FieldName);
grid.Children.Add(label);
return grid;
});
this.DisplayTemplate = displayTemplate;
}
It's simple, use name of property
label.SetBinding(BindingContextProperty, "Source");
I realised that storyboard only working with silverlight Wp 8.1 apps. So what about non-silverlight? I've want to make an animation of smooth appearing elements of listview after page transition. How can i make it? I check VisualStateGroup, but to make animation like that i should make a code behind. Is it possible to make only by XAML?
If you want to use XAML you can use the built in transitions which you can choose from already predefined ones. One drawback is that you can't create your own transitions this way.
To change the item transitions change the ItemContainerTransitions property on your ListView:
<ListView x:Name="MyListView">
<ListView.ItemContainerTransitions>
<TransitionCollection>
<!--<ContentThemeTransition HorizontalOffset="0"/>-->
<!--<EntranceThemeTransition />-->
<!-- <AddDeleteThemeTransition /> -->
<!-- <RepositionThemeTransition/> -->
<!-- <ReorderThemeTransition /> -->
<!-- <PopupThemeTransition/> -->
<!-- <EdgeUIThemeTransition Edge="Top"/> -->
</TransitionCollection>
</ListView.ItemContainerTransitions>
</ListView>
You can combine them if you want. Just uncomment any of the above code and use which suits you best.
You can create custom item animations when you extend ListView and override the GetContainerForItemOverride or PrepareContainerForItemOverride methods. You can use XAML if you want for example a Storyboard defined in as a StaticResource. Here is an example:
public class MyListView : ListView
{
protected override DependencyObject GetContainerForItemOverride()
{
var container = base.GetContainerForItemOverride();
var da = new DoubleAnimation();
// init da...
var sb = new Storyboard();
// initi sb with container
sb.Begin();
return container;
}
protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
{
base.PrepareContainerForItemOverride(element, item);
var da = new DoubleAnimation();
// init da...
var sb = new Storyboard();
// initi sb with element
sb.Begin();
}
}