如何在Xamarin.Forms中设置ContentPage的方向

8
我正在使用Xamarin.Forms创建跨平台应用程序,所有的ContentPages都位于PCL中。 我正在寻找一种方法来设置和锁定单个ContentPage的方向为Landscape,最好不必在每个特定平台的项目中创建另一个activity。 由于我的ContentPage.Content设置为ScrollView,因此我尝试将ScrollOrientation设置为Horizontal,但这并没有起作用。 我还尝试使用RelativeLayout,但我看不到该属性的方向。
public class PlanningBoardView : ContentPage //Container Class.
    {
        public PlanningBoardView()
        {
            scroller = new ScrollView ();

            Board = new PlanningBoard();

            scroller.Orientation = ScrollOrientation.Horizontal;
            scroller.WidthRequest = Board.BoardWidth;
            scroller.Content = Board;

            Content = scroller;
        }
    }

我最后尝试的是使用Xamarin Studio的Intellisense版本和Xamarin Forms API Doc's浏览可用于我的不同布局,但没有一个布局有Orientation属性。
我担心唯一的方法是创建第二个特定于平台的Activity,仅用于此ContentPage并将方向设置为横向。
虽然这种方法可以工作,但使屏幕之间的导航更加复杂。
目前正在Android中测试。
4个回答

15
抱歉要说这个,但只能使用自定义渲染器或特定平台的代码来完成。
在Android中,您可以将MainActivity的RequestedOrientation属性设置为ScreenOrientation.Landscape
在iOS中,您可以重写AppDelegate类中的GetSupportedInterfaceOrientations方法,以返回一个UIInterfaceOrientationMask值,当Xamarin.Forms.Application.Current.MainPage是您感兴趣的ContentPage时。

安卓

[assembly: Xamarin.Forms.ExportRenderer(typeof(MyCustomContentPage), typeof(CustomContentPageRenderer))]

public class CustomContentPageRenderer : Xamarin.Forms.Platform.Android.PageRenderer
{
    private ScreenOrientation _previousOrientation = ScreenOrientation.Unspecified;

    protected override void OnWindowVisibilityChanged(ViewStates visibility)
    {
        base.OnWindowVisibilityChanged(visibility);

        var activity = (Activity)Context;

        if (visibility == ViewStates.Gone)
        {
            // Revert to previous orientation
            activity.RequestedOrientation = _previousOrientation == ScreenOrientation.Unspecified ? ScreenOrientation.Portrait : _previousOrientation;
        }
        else if (visibility == ViewStates.Visible)
        {
            if (_previousOrientation == ScreenOrientation.Unspecified)
            {
                _previousOrientation = activity.RequestedOrientation;
            }

            activity.RequestedOrientation = ScreenOrientation.Landscape;
        }
    }
}

iOS

public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
{
    public override UIInterfaceOrientationMask GetSupportedInterfaceOrientations(UIApplication application, UIWindow forWindow)
    {
        if (Xamarin.Forms.Application.Current == null || Xamarin.Forms.Application.Current.MainPage == null)
        {
            return UIInterfaceOrientationMask.Portrait;
        }

        var mainPage = Xamarin.Forms.Application.Current.MainPage;

        if (mainPage is MyCustomContentPage ||
           (mainPage is NavigationPage && ((NavigationPage)mainPage).CurrentPage is MyCustomContentPage) ||
           (mainPage.Navigation != null && mainPage.Navigation.ModalStack.LastOrDefault() is MyCustomContentPage))
        {
            return UIInterfaceOrientationMask.Landscape;
        }

        return UIInterfaceOrientationMask.Portrait;
    }
}

有没有示例的机会?(Android可以) - KidCode
当然可以。我编辑了我的回答。这个例子将强制横屏模式,但你可以根据自己的需求进行更改。 - Dealdiane
我已经实现了iOS版本,但它不会自动旋转...这可能吗? - GBreen12
自动旋转是什么意思?你是指强制某个方向吗?当然可以。这就是代码的全部意义。也许如果您能提供一个最小可复现示例(MCVE)(并可能创建另一个问题?),更多人可以为您提供指导。 - Dealdiane

2

可以使用MessagingCenter类将来自Form项目的消息发送到主机项目,而无需使用自定义渲染器或依赖服务,方法如下:

public partial class ThirdPage : ContentPage
  {
      protected override void OnAppearing()
      { 
          base.OnAppearing(); 
         MessagingCenter.Send(this, "allowLandScapePortrait");
      }
       //during page close setting back to portrait
      protected override void OnDisappearing()
      {
          base.OnDisappearing(); 
          MessagingCenter.Send(this, "preventLandScape");
      }
  }

更改MainActivity以接收消息并设置RequestedOrientation

[Activity(Label = "Main", ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation,ScreenOrientation = ScreenOrientation.Portrait)]
 public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsApplicationActivity
  {        
  //allowing the device to change the screen orientation based on the rotation
  MessagingCenter.Subscribe<ThirdPage>(this, "allowLandScapePortrait", sender =>
  { 
   RequestedOrientation = ScreenOrientation.Unspecified;
  });
 //during page close setting back to portrait
 MessagingCenter.Subscribe<ThirdPage>(this, "preventLandScape", sender =>
  { 
   RequestedOrientation = ScreenOrientation.Portrait;
  });
 }

在我的博客文章中了解更多: http://www.appliedcodelog.com/2017/05/force-landscape-or-portrait-for-single.html


1

0

Dealdiane的代码对我来说很好用,只需要做出小修改:

protected override void OnWindowVisibilityChanged(ViewStates visibility) {
    base.OnWindowVisibilityChanged( visibility );

    IRotationLock page = Element as IRotationLock;
    if ( page == null )
        return;

    var activity = (Activity) Context;

    if ( visibility == ViewStates.Gone ) {
        // Revert to previous orientation
        activity.RequestedOrientation = _previousOrientation;
    } else if ( visibility == ViewStates.Visible ) {
        if ( _previousOrientation == ScreenOrientation.Unspecified ) {
            _previousOrientation = activity.RequestedOrientation;
        }

        switch ( page.AllowRotation() ) {
            case RotationLock.Landscape:
                activity.RequestedOrientation = ScreenOrientation.SensorLandscape;
                break;
            case RotationLock.Portrait:
                activity.RequestedOrientation = ScreenOrientation.SensorPortrait;
                break;
        }
    }
}

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