在Xamarin.Forms中实现屏幕方向切换时添加布局

5

我需要实现的是,在屏幕从竖向变为横向时,向现有页面添加布局。我已经使用void OnSizeAllocated(double width, double height)成功检测到屏幕方向的变化。但是我不能在此事件上添加布局。

我的示例C#代码如下:

   public class MyLayoutView : ContentPage
   {
      StackLayout portraitcontent = null;
      StackLayout landscapecontent = null;
      StackLayout footer = null;

   public MyLayoutView ()
    {

    portraitcontent = new StackLayout ();
    landscapecontent = new StackLayout ();
    footer = new StackLayout ();

    this.Padding = new Thickness(0, Device.OnPlatform(20, 0, 0), 0, 0);
    this.BackgroundColor = Color.FromHex ("#ffffff");
    this.Content = new StackLayout
        {
            Children =
            {
                portraitcontent ,
                landscapecontent ,
                footer 
            }
            };
         }
   }

OnSizeAllocated Method

   protected override void OnSizeAllocated(double width, double height)
    {
        base.OnSizeAllocated(width, height);

        if (width < height) {
            // In Portrait
            portraitcontent .IsVisible = true;
            landscapecontent.IsVisible = false;
            Debug.WriteLine ("Application Is in portrait");
        } else {
            // In Landscape
            portraitcontent .IsVisible = false;
            landscapecontent.IsVisible = true;

            landscapecontent.Children.Clear ();

            Label LandscapeLabel= new Label
            {
              Text = "<Each Time Text Changes>",
              HorizontalOptions = LayoutOptions.StartAndExpand,
              TextColor=Xamarin.Forms.Color.FromHex("#000000")
            };

            landscapecontent.Children.Add(LandscapeLabel); 

            Debug.WriteLine ("Application Is in Landscape");
        }
    }

当防止重入时,它会抛出“无法修改集合”错误。每次方向改变时,我需要在stacklayout中添加一个新标签。有什么适当的方法可以实现吗?

提前感谢。

4个回答

5

覆盖OnSizeAllocated可能不是最佳方法。我只是将其放在我的代码中,从纵向到横向时,该方法会被调用大约25次。

我尝试的另一件事是在表单页面上挂接事件处理程序:

this.SizeChanged += (sender, e) => setOrientation(this);    // Connect Orientation Switcher

为了跟踪真正的页面旋转并避免处理器做不必要的工作,我创建了一个类变量来存储当前状态,然后将其添加到高度/宽度比较中。
void setOrientation (Page p)
     if ( isPortrait && (p.Width > p.Height) ) { do stuff }
     if ( !isPortrait && (p.Width < p.Height) ) { do stuff }

那个方法确实更快,但目前似乎会出现内存泄漏问题,因为一些布局来回切换。我们正在努力解决这个问题。我无法相信,在移动设备旋转屏幕已经有好几年的情况下,一个开发工具没有一个简单易用的库可以做这件事。他们似乎可以让我们连接几个不同的布局到一个页面,并根据环境自动选择运行时。也许这对于我来说并不困难,但我不是开发人员,所以可能比我想象的要难得多。
如果我最终成功实现旋转功能,我会尝试回来发布代码。

3

当屏幕方向改变时,会多次调用OnSizeAllocated方法。我认为你需要进行更多的验证,例如检查子视图的数量,以避免视图的重复。

    if(landscapecontent.Children.Count>1)
     { 
       //Don't add any views
     }

只要我尝试过,就没有旋转的事件处理程序。在代码中进行一些技巧性的更改以在方向改变时改变视图。
即使您可以使用此处提供的答案。希望它能为您服务。

0

对于Xamarin Forms,PCL是错误的层来检测方向变化。您需要使用特定于平台的代码来检测它们,然后将其传达到PCL。 对于我现在正在开发的项目,这是我的解决方案: 在PCL代码中:

public interface IOrientation
    {
        AppOrientation CurrentOrientation { get; }
        IObservable<AppOrientation> Orientation { get; }
    }

    public enum AppOrientation
    {
        Unknown = 0,
        Portrait,
        Landscape
    }

在任何关心方向变化的视图(XAML页面)中,我可以这样观察方向变化: 我使用autofac在构造函数中初始化IOrientation,在您认为最适合的Ioc或服务解析中使用它。
public HomePage(IViewResolver resolver,IOrientation orientation)
{
    InitializeComponent();
     _resolver = resolver;
     this.SetContent();
     orientation.Orientation.ObserveOn(SynchronizationContext.Current)
     .Subscribe(x => this.SetContent());
}

针对 Android:

在 MainActivity.cs 中,实现 MainActivity 的 IOrientation 接口。 public class MainActivity:global :: Xamarin.Forms.Platform.Android.FormsApplicationActivity ,IErrorReporting,IOrientation 并在构造函数中的某个位置添加: _lastOrientation = this.Resources.Configuration.Orientation;

 #region IOrientation
        private Android.Content.Res.Orientation _lastOrientation;
        private readonly Subject<AppOrientation> _orientation = new Subject<AppOrientation>();

        public AppOrientation CurrentOrientation
        {
            get
            {
                return _lastOrientation == Android.Content.Res.Orientation.Portrait ? AppOrientation.Portrait :
                    _lastOrientation == Android.Content.Res.Orientation.Landscape ? AppOrientation.Landscape : 
                    AppOrientation.Unknown;
            }
        }
    public IObservable<AppOrientation> Orientation { get { return _orientation; } }

    public override void OnConfigurationChanged(Configuration newConfig)
    {
        base.OnConfigurationChanged(newConfig);
        if (newConfig.Orientation == this._lastOrientation)  return; 
        this._lastOrientation = newConfig.Orientation;

        this._orientation.OnNext(this.CurrentOrientation);

    }

    #endregion

在iOS中扩展Appdelegate ``` public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate, IOrientation ``` 并且在构造函数的某个地方: ``` _lastOrientation = UIDevice.CurrentDevice.Orientation; ```
#region IOrientation

    private UIDeviceOrientation _lastOrientation = UIDeviceOrientation.Unknown;
    private readonly Subject<AppOrientation>  _orientation=new Subject<AppOrientation>();

    public AppOrientation CurrentOrientation
    {
        get
        {
            return
                (_lastOrientation == UIDeviceOrientation.LandscapeLeft || _lastOrientation == UIDeviceOrientation.LandscapeRight) ? AppOrientation.Landscape :
                (_lastOrientation == UIDeviceOrientation.Portrait || _lastOrientation == UIDeviceOrientation.PortraitUpsideDown) ? AppOrientation.Portrait : 
                AppOrientation.Unknown;
        }
    }

    public IObservable<AppOrientation> Orientation { get { return _orientation; } }

    #endregion

我没有 WP 实现,但我不相信创建一个会很难....


0
希望不算太晚。对我来说,使用 Xamarin.Essentials 是更简单的解决方案。

Model.cs

using Xamarin.Essentials;
.
.
.
private DisplayOrientation orientation = DeviceDisplay.MainDisplayInfo.Orientation;
public DisplayOrientation Orientation
{
    get => orientation;
    set => orientation = value;
}

View.xaml.cs

using Xamarin.Essentials;
.
.
.
protected override void OnSizeAllocated(double width, double height)
{
    base.OnSizeAllocated(width, height);
    model.Orientation = DeviceDisplay.MainDisplayInfo.Orientation;
}

View.xaml

<ContentPage xmlns:ess="clr-namespace:Xamarin.Essentials;assembly=Xamarin.Essentials">
    <ContentPage.BindingContext>
        <!--Model here-->
    </ContentPage.BindingContext>
    <DataTrigger TargetType="..."
        Binding="{Binding Orientation}"
        Value="{x:Static ess:DisplayOrientation.Portrait}">
            <Setter Property="..." Value="..." />
    </DataTrigger>
    <DataTrigger TargetType="..."
        Binding="{Binding Orientation}"
        Value="{x:Static ess:DisplayOrientation.Landscape}">
            <Setter Property="..." Value="..." />
    </DataTrigger>
</ContentPage>

不要忘记 INotifyPropertyChanged 的影响。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接