繁体   English   中英

Xamarin.Forms ListView放在StackLayout中

[英]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 我还玩过HeightRequestCameraView但是,我不想设置摄像机视图的特定高度,我希望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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM