如何在Xamarin中的ScrollView内的StackLayout中正确使用AbsoluteLayout?

时间:2016-04-22 02:36:07

标签: xamarin xamarin.forms

好的,我放弃了。尝试完成这个简单的事情花了3天时间。

这是我的场景(并非所有在同一个XAML文件中):

<TabbedPage>
  <NavigationPage>
    <ContentPage/>
    <ContentPage/>
    <CarouselPage>
      <CarouselContentPage>

这是CarouselContentPage

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MyApp.Layouts.PointInfoDataTemplate"
             >
  <ContentPage.Content>  
    <ScrollView Orientation="Vertical" BackgroundColor="Navy" VerticalOptions="Fill">
      <StackLayout x:Name="MyStackLayout" HorizontalOptions="StartAndExpand" VerticalOptions="Start" BackgroundColor="Gray">
        <Label x:Name="NameLabel" FontSize="Medium" HorizontalOptions="Center"/>
        <Label x:Name="DescLabel" FontSize="Medium" HorizontalOptions="Center" />
        <AbsoluteLayout x:Name="ImgsContainer" VerticalOptions="Start" BackgroundColor="Green">
          <Image x:Name="BackImg" Aspect="AspectFit" VerticalOptions="Start"/>
          <Image x:Name="MidImg" Aspect="AspectFit" VerticalOptions="Start"/>
          <Image x:Name="FrontImg" Aspect="AspectFit" VerticalOptions="Start"/>
        </AbsoluteLayout>
      </StackLayout>
    </ScrollView>
  </ContentPage.Content>
</ContentPage>

我需要的是简单的,垂直滚动页面上有一些垂直堆叠的标签,之后我需要创建“一个图像”,它由3个图像组成,彼此重叠(如3层重叠)。为此,我需要AbsoluteLayout仅用于图像,对吗?

我已经为此文件中的所有视图尝试了VerticalOptions的所有可能组合,但没有任何效果。

问题是滚动总是在图像下面留下很大的空间。并且使用绿色,这意味着AbsoluteLayout在图像调整大小后不会缩小其高度。图像可以具有可变的大小和形状(尽管每个页面内的3个都具有相同的尺寸)并且它们都比任何智能手机屏幕都大(稍后的缩放功能)。所以我需要图像使用所有可用的宽度并保持纵横比(我相信AspectFit)。

所有图片均为嵌入式资源。以下是CarouselContentPage背后的代码:

public PointInfoDataTemplate(PointModel point)
{
    InitializeComponent();
    NameLabel.Text = point.nome;
    DescLabel.Text = point.apelido;
    BackImg.Source = ImageSource.FromResource(point.backimg);
    MidImg.Source = ImageSource.FromResource(point.midimg);
    FrontImg.Source = ImageSource.FromResource(point.frontimg);
    //BackImg.SizeChanged += delegate {
    //    ImgsContainer.Layout(new Rectangle(imgsContainer.Bounds.X, imgsContainer.Bounds.Y, BackImg.Bounds.Width, BackImg.Bounds.Height));
    //    MyStackLayout.Layout(new Rectangle(imgsContainer.Bounds.X, imgsContainer.Bounds.Y, BackImg.Bounds.Width, BackImg.Bounds.Height));
    //};
}

我甚至在SizeChanged事件后尝试调整了Layouts的大小,但它也没有用。

所以也许我做错了,这是我的所有代码。我被困了3天,我不知道还能做什么。

我尝试使用RelativeLayout作为ScrollView.Content。经过一整天试图理解它(并且不确定我是否完全做到了),我遇到了更糟糕的问题。 RelativeLayout会溢出Scroll高度并隐藏标签后面的部分图片(基本应用容器)。

但我真的想保留StackLayout->items + AbsoluteLayout方法。

我感谢任何帮助。

3 个答案:

答案 0 :(得分:2)

我发现问题出在AbsoluteLayout未处理其子调整大小事件上。要么Image元素没有调度正确的事件,要么AbsoluteLayout没有很好地处理它们。 所以我需要的只是创建这个事件处理。 添加了Image.SizeChanged的监听器以设置AbsoluteLayout高度。

        private void BackImg_SizeChanged(object sender, EventArgs e)
        {
            ImgsContainer.HeightRequest = BackImg.Height;
        }

这适用于我的情况,但是如果你对AbsoluteLayout有更复杂的子处理,你将需要这样的东西:

private void ChildAdded_EventHandler(object sender, EventArgs e) {
    double neededHeight = 0;
    foreach(var child in sender) {
        if(neededHeight < child.Y+child.Height) {
            neededHeight = child.Y+child.Height;
        }
    }
    sender.HeightRequest = neededHeight;
}

您必须将此事件处理程序添加到AbsoluteLayout.ChildAddedAbsoluteLayout.ChildRemoved;

答案 1 :(得分:1)

它在C#中不是XAML,但它应该很容易转换

Grid imageContainer = new Grid() {    
    HeightRequest = 400,

    Children = {
        new Image(), //Image 1
        new Image(), //Image 2 on top of image 1
        new Image(), //Image 3 on top of image 2 and 1
    }
}

Content = new ScrollView() {    
    Content = new Grid() {
        RowDefinitions = {
            new RowDefinition(){Height = new GridLength(1, GridUnitType.Auto)}, //label1
            new RowDefinition(){Height = new GridLength(1, GridUnitType.Auto)}, //label2
            new RowDefinition(){Height = new GridLength(1, GridUnitType.Auto)}, //image container
        },

        Children ={
            {new Label(), 0, 0},   //Label 1
            {new Label(), 0, 1},   //Label 2
            {imageContainer, 0, 2} //image container
        }
    }
};

答案 2 :(得分:1)

如果网格解决方案有效,那可能会更容易,但因为您询问了AbsoluteLayout ......

要使AbsoluteLayout正常工作,您不要在子项上使用与其他视图相同的VerticalOptions。

相反,还有其他方法可以准确指出如何布置与绝对布局相关的孩子。使用C#代替Xaml,您可以执行以下操作:

AbsoluteLayout.SetLayoutFlags(BackImg,
     AbsoluteLayoutFlags.PositionProportional);
AbsoluteLayout.SetLayoutBounds(BackImg,
     new Rectangle(0, 0, AbsoluteLayout.AutoSize, AbsoluteLayout.AutoSize));

对于MidImg和FrontImg也是如此。

SetLayoutFlags告诉系统子项的大小和/或位置的哪些方面与父项成比例。然后SetLayoutBounds提供了如何布局的详细信息。在这种情况下,代码说要在左上角布置BackImg。