在动画之前获取 Xamarin.Forms ContentView 的高度

Kri*_*rge 3 xamarin xamarin.forms

我正在尝试创建一个从 Xamarin.Forms 页面顶部发出动画的通知。我非常接近,但在页面上设置 ContentView 的动画之前我无法获取 ContentView 的高度。我制作了一个 xamarin工作簿来演示我的问题,可以在 android 模拟器上运行。(猜测它也可以在 ios/wpf 上工作,并进行一些修改)

该工作簿可在此处获取

问题在于ToastNotificationView.AnimateIn()我首先将整个内容视图的可见性设置为可见(红色背景)。尽管在动画化之前多次尝试将其位置设置在屏幕外,但绿色通知会立即呈现在其最终位置。这种情况仅在通知第一次在页面上动画化时发生,因为它的高度在动画化后可用离开屏幕并再次隐藏。

我可以通过将高度偏移硬编码为 50 来解决这个问题,但要实现可变高度的一致动画,这并不能解决问题。我还可以创建一个方法来计算行数,然后根据该方法动态设置高度,但我希望有一种方法可以实际渲染它,并以某种方式获取组件的实际高度,而不使其对用户可见直到我从我想要的地方开始动画。

public class ToastNotificationView: ContentView {
    // The notification item to be animated in/out
    private StackLayout MainStackLayout;
    public ToastNotificationView() {
        InitializeComponent(); // Let's pretend workbooks supports xaml

        //Subscribing to notification events
        NotificationService.NotificationAppearing += AnimateIn;
        // TODO: Find out how to unsubscribe in contentview without access to life cycle hooks
    }
    private async void OnDismissClicked(object sender, EventArgs e) {
        await AnimateOut();
    }
    private async Task AnimateOut() {
        await MainStackLayout.TranslateTo(0, -MainStackLayout.Height, 1000);
        IsVisible = false;
    }
    private async void AnimateIn(object sender, EventArgs e) {
        // Make the entire view visible
        IsVisible = true;

        // First time, height is always zero, so we can't set it like this
        MainStackLayout.TranslationY = -MainStackLayout.Height;

        // Attempting to await a 1ms animation to get a height does not result in correct height either
        await MainStackLayout.TranslateTo(0, 0, 1);
        await MainStackLayout.TranslateTo(0, -MainStackLayout.Height, 1);

        //Still does not animate in on initial animation
        await MainStackLayout.TranslateTo(0, 0, 1000);
    }
}
Run Code Online (Sandbox Code Playgroud)

布局是在 InitializeComponent 方法中创建的,以支持 xamarin 工作簿。就本问题而言,这可以是任何内容。

// layout
private void InitializeComponent(){
    // Make contentview background red for debugging purposes
    this.BackgroundColor = Color.Red;
    this.VerticalOptions = LayoutOptions.Start;

    //The actual notification should be green
    MainStackLayout = new StackLayout{
        Orientation = StackOrientation.Horizontal,
        VerticalOptions = LayoutOptions.Start,
        BackgroundColor = Color.Green
    };
    var title = new Label{
        Text = "Hello There"
    };
    var msg = new Label{
        Text = "Importaint stuff you should be aware of"
    };

    var btn = new Button{
        Text = "X",
        VerticalOptions = LayoutOptions.Start,
        HorizontalOptions = LayoutOptions.EndAndExpand,
        BorderColor = Color.Transparent,
        BackgroundColor = Color.Transparent,
        HeightRequest = 40,
        WidthRequest = 40,
        Margin = 3
    };
    btn.Clicked += OnDismissClicked;
    var textStack = new StackLayout();
    textStack.Children.Add(title);
    textStack.Children.Add(msg);
    MainStackLayout.Children.Add(textStack);
    MainStackLayout.Children.Add(btn);
    Content = MainStackLayout;

    // Default visibility is hidden
    IsVisible = false;

}
Run Code Online (Sandbox Code Playgroud)

Dan*_*l P 5

您可以使用以下方法Measure获取高度:

private async void AnimateIn(object sender, EventArgs e)
{
    var parent = (VisualElement)Parent;
    SizeRequest sizeRequest = MainStackLayout.Measure(parent.Width, parent.Height);

    MainStackLayout.TranslationY = -sizeRequest.Request.Height;

    IsVisible = true;

    await MainStackLayout.TranslateTo(0, 0, 1000);
}
Run Code Online (Sandbox Code Playgroud)