I am developing a user interface in Xamarin.Forms to collect user feedback about our application. There is an editor at the bottom of this page. On the iPhone 4S and in many landscape orientations, the keyboard completely covers this editor control. On Android, this is not very important, because the OS automatically scrolls (although the calibration behavior is a bit strange.) On iOS, the only things that look like solutions are very exciting.
In the original iOS, the solution is simple: wrap your views in a UIScrollView, and then when the keyboard appears, add so much space to the content size and scroll it accordingly. Xamarin doesn't reveal anything to control the scroll position in ScrollView, and ContentSize is private, so this is not possible. A few posts ( here and here ) show that ScrollView is at least partially a solution. Xamarin seems to have some kind of automatic scrolling, but that's ... curious.
My layout is pretty simple:
- At the top is a fixed navigation bar, which I don’t want to scroll out of sight.
- Below it is an image with a height of 180 pixels, which is a screenshot of the application.
- Below this is a timestamp with information such as a timestamp. (2-3 lines of text).
- Under this, the editor, filling in the remaining free space.
I included the code for the layout that I tried at the bottom of the post. I created a StackLayout containing an image, label, and editor. I put this inside a ScrollView. Then I create a RelativeLayout and place the navigation bar in the upper left using the ScrollView below it.
, , , - , , , , . , Xamarin , , . , .
, . ScrollView, . , BoxView, , , , iOS, , . .
- Xamarin.Forms? , .
( , , , . .)
using System;
using Xamarin.Forms;
namespace TestScroll
{
public class MainPage : ContentPage {
public MainPage() {
InitializeComponent();
}
private ScrollView _scroller;
protected void InitializeComponent() {
var mainLayout = new RelativeLayout();
var navbar = new Label() {
BackgroundColor = Color.Blue,
TextColor = Color.White,
Text = "I am the Nav Bar",
HorizontalOptions = LayoutOptions.FillAndExpand,
VerticalOptions = LayoutOptions.StartAndExpand
};
var subLayout = new ScrollView() {
VerticalOptions = LayoutOptions.FillAndExpand,
HorizontalOptions = LayoutOptions.FillAndExpand
};
_scroller = subLayout;
var subStack = new StackLayout();
subStack.Spacing = 0;
subLayout.Content = subStack;
var image = new BoxView() {
Color = Color.Green,
HorizontalOptions = LayoutOptions.FillAndExpand,
VerticalOptions = LayoutOptions.Fill,
HeightRequest = 300
};
subStack.Children.Add(image);
var infoLabel = new Label() {
BackgroundColor = Color.Blue,
TextColor = Color.Black,
Text = "Timestamp!\r\nOther stuff!",
VerticalOptions = LayoutOptions.Start
};
subStack.Children.Add(infoLabel);
var editor = new Editor() {
VerticalOptions = LayoutOptions.FillAndExpand
};
subStack.Children.Add(editor);
mainLayout.Children.Add(navbar,
Constraint.Constant(0),
Constraint.Constant(20),
Constraint.RelativeToParent((parent) => parent.Width),
Constraint.Constant(70));
mainLayout.Children.Add(subLayout,
Constraint.Constant(0),
Constraint.RelativeToView(navbar, (parent, view) => navbar.Bounds.Bottom),
Constraint.RelativeToParent((parent) => parent.Width),
Constraint.RelativeToView(navbar, TestConstraint));
Content = mainLayout;
}
private double TestConstraint(RelativeLayout parent, View view) {
double result = parent.Height - view.Bounds.Height;
Console.WriteLine ("Lower stack height : {0}", result);
Console.WriteLine ("Scroll content size: {0}", _scroller.ContentSize);
return result;
}
}
}