我的Xamarin项目中有一个相当简单的XAML表单,该表单应该以垂直的StackLayout
封装两个视图,顶部的CameraView
和ListView
在底部。 CameraView
将用尽大部分空间。 ListView
不得超过4-5个项目,但会在运行时更改。这是到目前为止的XAML:
<?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="Foo.CamPage"
xmlns:ctrl="clr-namespace:Foo.Controls">
<ContentPage.Content>
<StackLayout Orientation="Vertical">
<ctrl:CameraView HeightRequest="2000"/>
<StackLayout VerticalOptions="FillAndExpand">
<ListView>
<ListView.ItemsSource>
<x:Array Type="{x:Type x:String}">
<x:String>Entry 1</x:String>
<x:String>Entry 2</x:String>
</x:Array>
</ListView.ItemsSource>
</ListView>
</StackLayout>
</StackLayout>
</ContentPage.Content>
如您所见,我的第一个想法是将ListView
放入另一个嵌套的StackLayout
中。我还玩过HeightRequest
中的CameraView
,但是,我不想设置摄像机视图的特定高度,我希望ListView
占用所需的空间和CameraView
进行相应调整。可以在尺寸中定义百分比吗?
如果有帮助,请访问CameraView
:
namespace Foo.Controls
{
public class CameraView : View
{
public static readonly BindableProperty CameraProperty =
BindableProperty.Create(
propertyName: "Camera",
returnType: typeof(CameraOptions),
declaringType: typeof(CameraView),
defaultValue: CameraOptions.Rear);
public CameraOptions Camera
{
get { return (CameraOptions)GetValue(CameraProperty); }
set { SetValue(CameraProperty, value); }
}
public Func<Task<ImageSource>> TakePhotoAsync { set; get; }
public Func<CameraOptions, bool> SwitchCamera { set; get; }
}
}
这是关联的iOS渲染器:
[assembly: ExportRenderer(typeof(CameraView), typeof(CamPreviewRenderer))]
namespace Foo.iOS.Renderers
{
public class CamPreviewRenderer : ViewRenderer<CameraView, UICamPreview>
{
UICamPreview uiCameraPreview;
protected override void OnElementChanged(ElementChangedEventArgs<CameraView> e)
{
base.OnElementChanged(e);
if (Control == null)
{
uiCameraPreview = new UICamPreview(e.NewElement.Camera);
SetNativeControl(uiCameraPreview);
}
if (e.OldElement != null)
{
// Unsubscribe
uiCameraPreview.Tapped -= OnCameraPreviewTapped;
}
if (e.NewElement != null)
{
// Subscribe
uiCameraPreview.Tapped += OnCameraPreviewTapped;
}
}
void OnCameraPreviewTapped(object sender, EventArgs e)
{
if (uiCameraPreview.IsPreviewing)
{
uiCameraPreview.CaptureSession.StopRunning();
uiCameraPreview.IsPreviewing = false;
}
else
{
uiCameraPreview.CaptureSession.StartRunning();
uiCameraPreview.IsPreviewing = true;
}
}
}
}
这是UICamPreview
:
namespace Foo.iOS.Renderers
{
public class UICamPreview : UIView
{
AVCaptureVideoPreviewLayer previewLayer;
CameraOptions cameraOptions;
public event EventHandler<EventArgs> Tapped;
public AVCaptureSession CaptureSession { get; private set; }
public bool IsPreviewing { get; set; }
public UICamPreview(CameraOptions options)
{
cameraOptions = options;
IsPreviewing = false;
Initialize();
}
public override void Draw(CGRect rect)
{
base.Draw(rect);
previewLayer.Frame = rect;
}
public override void TouchesBegan(NSSet touches, UIEvent evt)
{
base.TouchesBegan(touches, evt);
OnTapped();
}
protected virtual void OnTapped()
{
var eventHandler = Tapped;
if (eventHandler != null)
{
eventHandler(this, new EventArgs());
}
}
void Initialize()
{
CaptureSession = new AVCaptureSession();
previewLayer = new AVCaptureVideoPreviewLayer(CaptureSession)
{
Frame = Bounds,
VideoGravity = AVLayerVideoGravity.ResizeAspectFill
};
var videoDevices = AVCaptureDevice.DevicesWithMediaType(AVMediaType.Video);
var cameraPosition = (cameraOptions == CameraOptions.Front) ? AVCaptureDevicePosition.Front : AVCaptureDevicePosition.Back;
var device = videoDevices.FirstOrDefault(d => d.Position == cameraPosition);
if (device == null)
{
return;
}
NSError error;
var input = new AVCaptureDeviceInput(device, out error);
CaptureSession.AddInput(input);
Layer.AddSublayer(previewLayer);
CaptureSession.StartRunning();
IsPreviewing = true;
}
}
}
任何提示表示赞赏。
答案 0 :(得分:0)
将这些视图放入带有2行的Grid中。一个您想使用所需空间的地方将Height设置为Auto,另一个假设要占用剩余空间的视图将Height设置为*。像这样
<ContentPage.Content>
<StackLayout Orientation="Vertical">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<ctrl:CameraView Grid.Row="0"/>
<StackLayout VerticalOptions="FillAndExpand" Grid.Row="1">
<ListView>
<ListView.ItemsSource>
<x:Array Type="{x:Type x:String}">
<x:String>Entry 1</x:String>
<x:String>Entry 2</x:String>
</x:Array>
</ListView.ItemsSource>
</ListView>
</Grid>
</StackLayout>
</StackLayout>
</ContentPage.Content>
请记住,就布局而言,ListView是一个非常麻烦的问题。无论如何,您可能都需要设置“高度”的硬编码值。
答案 1 :(得分:0)
您尝试覆盖OnLayout时,通常的代码是这样的。
protected override void OnLayout(bool changed, int l, int t, int r, int b)
{
try
{
base.OnLayout(changed, l, t, r, b);
if (!changed)
return;
int msw = 50;
int msh = 50;
int layoutWidth = r - l;
int layoutHeight = b - t;
msw = MeasureSpec.MakeMeasureSpec(layoutWidth, MeasureSpecMode.Exactly);
msh = MeasureSpec.MakeMeasureSpec(layoutHeight, MeasureSpecMode.Exactly);
view.Measure(msw, msh);
view.Layout(0, 0, layoutWidth, layoutHeight);
}
catch (System.Exception ex)
{
Logger.WriteException(ex);
}
}