[英]Xamarin.Forms ListView inside StackLayout
在我的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;
}
}
}
任何提示表示赞赏。
将这些视图放入带有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是一个非常麻烦的问题。 无论如何,您可能都需要为“高度”设置硬编码值。
您是否尝试覆盖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); } }
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.