Activity横竖屏切换-创新互联

默认情况下,当“屏幕方向”或“键盘显示隐藏” 变化时都会销毁当前Activity,创建新的Activity。

公司主营业务:成都网站设计、成都网站制作、移动网站开发等业务。帮助企业客户真正实现互联网宣传,提高企业的竞争能力。创新互联公司是一支青春激扬、勤奋敬业、活力青春激扬、勤奋敬业、活力澎湃、和谐高效的团队。公司秉承以“开放、自由、严谨、自律”为核心的企业文化,感谢他们对我们的高要求,感谢他们从不同领域给我们带来的挑战,让我们激情的团队有机会用头脑与智慧不断的给客户带来惊喜。创新互联公司推出峄城免费做网站回馈大家。

如果不希望重新创建Activity实例,可以按如下配置Activity:

注意Android3.2横竖屏幕切换时以上配置configChanges要加上screenSize,要不还会调用onCreate

上面的android:configChanges属性指定了要捕获“屏幕方向”和“键盘显示隐藏”变化,

当捕获到这些变化后会调用Activity的onConfigurationChanged()方法。

默认情况下(没有配置android:configChanges属性):

竖屏切横屏,销毁当前Activity之后,创建一个新Activity实例。

横屏切竖屏,销毁当前Activity之后,创建一个新Activity实例,新的Activity实例很快就被销毁,接着又会创建一个新Activity实例。如果只希望创建一个实例,可以配置android:configChanges="orientation"

  

    android:screenOrientation="portrait"  //竖屏

    android:screenOrientation="landscape"  //横屏

  />

上述修改也可以在Java代码中通过类似如下代码来设置

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE)

android:screenOrientation属性

他有以下几个参数:

  "unspecified":默认值 由系统来判断显示方向.判定的策略是和设备相关的,所以不同的设备会有不同的显示方向.

  "landscape":横屏显示(宽比高要长)

  "portrait":竖屏显示(高比宽要长)

  "user":用户当前选的方向

  "behind":和该Activity下面的那个Activity的方向一致(在Activity堆栈中的)

  "sensor":有物理的感应器来决定。如果用户旋转设备这屏幕会横竖屏切换。

  "nosensor":忽略物理感应器,这样就不会随着用户旋转设备而更改了("unspecified"设置除外)。

APP的横竖屏切换手动触发

  由上面描述可知,当android:screenOrientation为默认值"unspecified"或"sensor"等时,就会有系统根据设备的旋转情况来触发横竖屏的切换,那么有没有方法我们手动在程序中触发横竖屏的变换呢,显然上面为我们提供的setRequestedOrientation就是系统提供的一个入口,下面我们给出一个按键的方式来触发的案列:

  public class MainActivity extends Activity implements OnClickListener {

    private Button mBtnLandscape;

    private Button mBtnPortrait;

    @Override

    protected void onCreate(Bundle savedInstanceState) {

      super.onCreate(savedInstanceState);

      setContentView(R.layout.activity_main);

      mBtnLandscape = (Button) findViewById(R.id.but_landscape);

      mBtnPortrait = (Button) findViewById(R.id.but_portrait);

      mBtnLandscape.setOnClickListener(this);

      mBtnPortrait.setOnClickListener(this);

    }

    @Override

    public void onClick(View v) {

      if(v == mBtnLandscape){

        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);

      }else{

        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

      }

    }

    @Override

    public void onConfigurationChanged(Configuration newConfig) {

      super.onConfigurationChanged(newConfig);

      String message=newConfig.orientation==Configuration.ORIENTATION_LANDSCAPE ? "屏幕设置为:横屏" : "屏幕设置为:竖屏";

      Toast.makeText(this, message, Toast.LENGTH_LONG).show();

    }

  }

  需要注意的是,手动调用时,无视AndroidManifest中关于screenOrientation的设置;另外上述代码中的onConfigurationChanged要被调用到也是需要条件的,在这里,只给代码,不做讨论,后面再给出一个相关的补充说明。

重启Activity的横竖屏切换

  在上面的案列中,缺省状态下,Activity每次横竖屏切换(包括用setRequestedOrientation调用)都会重新调用一轮onPause-> onStop-> onDestory-> onCreate->onStart->onResume操作,从而销毁原来的Activity对象,创建新的Activity对象,这是因为通常情况下软件在横竖屏之间切换,界面的高宽会发生转换,从而可能会要求不同的布局。具体的布局切换可以通过如下两种方法来实现:

  1)在res目录下建立layout-land和layout-port目录,相应的layout文件名不变,比如都为main.xml。layout-land是横屏的layout,layout-port是竖屏的layout,其他的不用管,横竖屏切换时模拟器自动寻找main.xml文件。

  2)假如布局资源是不一样又不按照如上设置,则需要通过java代码来判断当前是横屏还是竖屏然后来加载相应的xml布局文件(比如mainP为竖屏mainL为横屏)。因为当屏幕变为横屏的时候,系统会重新呼叫当前Activity的onCreate方法,你可以把以下方法放在你的onCreate中来检查当前的方向,然后可以让你的setContentView来载入不同的layout xml。

  @Override

  protected void onCreate(Bundle icicle) {

   super.onCreate(icicle);

   int mCurrentOrientation = getResources().getConfiguration().orientation;

   if ( mCurrentOrientation == Configuration.ORIENTATION_PORTRAIT ) {

     Log.i("info", "portrait"); // 竖屏

     setContentView(R.layout.mainP);

   } else if ( mCurrentOrientation == Configuration.ORIENTATION_LANDSCAPE ) {

     Log.i("info", "landscape"); // 横屏

     setContentView(R.layout.mainL);

   }

   init();//初始化,赋值等操作

   findViews();//获得控件

   setListensers();//设置控件的各种监听方法

  }

  上面只是对布局切换做了描述,实际上由于重启Activity在未加处理的情况下必然导致数据的丢失和重新获取,这样用户体验会非常差。为此就要在切换前对数据进行保存,切换重启后对数据进行恢复,具体操作的步骤如下:

  重写Activity.onRetainNonConfigurationInstance(),用户横竖屏切换前保存数据

  @Override

  public Object onRetainNonConfigurationInstance() {

    final MyDataObject data = collectMyLoadedData();

    return data;

  }

  在onCreate()函数中调用getLastNonConfigurationInstance(),获取onRetainNonConfigurationInstance()保存的数据

  @Override

  public void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

    setContentView(R.layout.main);

    final MyDataObject data = (MyDataObject) getLastNonConfigurationInstance();

    if (data == null) {

      data = loadMyData();

    }

    ...

  }

非重启Activity的横竖屏切换

  虽然重启Activity为我们提供了保存数据和读取数据的方式,但是如此一来程序会显得有些繁琐,所以有时候程序员往往就不想让Activity重启,Android也为我们提供了解决方案,就是通过onConfigurationChanged拦截横竖屏变换,从而进行必要的重新布局和切换操作。操作步骤如下:

  首先,manifest中为相应的Activity设置android:configChanges属性,从而让Activity不延续上述的重建流程,具体如下:

  Andorid 3.2以前的SDK可以使用如下配置

  android:configChanges="orientation|keyboardHidden"

  而Adnroid 3.2以后的SDK必须添加一个screenSize属性,具体如下

  android:configChanges="keyboardHidden|orientation|screenSize"

  或者

  android:configChanges="orientation|screenSize"

  其次,在Activity或View的onConfigurationChanged(Configuration newConfig)函数中获取当前横竖屏参数。至于其调用顺序跟touch事件的传递顺序相似,不过他没有消费事件的概念,会顺次调用到每一个onConfigurationChanged函数。下面是重写Activity的例子:

  //布局分别在layout-land和layout-port目录中的同名main.xml时

  @Override

  public void onConfigurationChanged (Configuration newConfig){

    super.onConfigurationChanged(newConfig);

    setContentView(R.layout.main);

    //注意,这里删除了init(),否则又初始化了,状态就丢失

    findViews();

    setListensers();

  }

  //布局为不按照layout-land和layout-port目录,而自定义名字时

  @Override

  public void onConfigurationChanged (Configuration newConfig){

    super.onConfigurationChanged(newConfig);

    int mCurrentOrientation = getResources().getConfiguration().orientation;

    if ( mCurrentOrientation == Configuration.ORIENTATION_PORTRAIT ) {

      setContentView(R.layout.mainP);

      //注意,这里删除了init(),否则又初始化了,状态就丢失

      findViews();

      setListensers();

    } else if ( mCurrentOrientation == Configuration.ORIENTATION_LANDSCAPE ) {

      setContentView(R.layout.mainL);

      //注意,这里删除了init(),否则又初始化了,状态就丢失

      findViews();

      setListensers();

    }

  }

  当然有时候连布局都不用更改的话,就可以直接对原有控件进行调用操作了,比如:

  public class MainActivity extends Activity {

    private TextView textView;

    @Override

    public void onCreate(Bundle savedInstanceState) {

      super.onCreate(savedInstanceState);

      setContentView(R.layout.main);

      Log.i("--Main--", "onCreate");

      textView=(TextView)findViewById(R.id.tv_id);

    }

    @Override

    public void onConfigurationChanged(Configuration newConfig) {

      super.onConfigurationChanged(newConfig);

      Log.i("--Main--", "onConfigurationChanged");

      if(newConfig.orientation==Configuration.ORIENTATION_LANDSCAPE){

        textView.setText("当前屏幕为横屏");

      }else{

        textView.setText("当前屏幕为竖屏");

      }

    }

  }

  需要注意的是,onConfigurationChanged函数中只能获得横竖屏切换后的参数,在该函数中获取不到新的Layout和控件的尺寸位置信息,如果要处理尺寸和位置信息,必须通过消息异步或者延时调用,下面是一个App在横竖屏切换时需要重新设置popupWindow位置的代码:

  @Override

  protected void onConfigurationChanged(Configuration newConfig) {

    super.onConfigurationChanged(newConfig);

    //View中不用创建Handler,可直接调用post操作

    //new Handler().postDelayed(new Runnable() {

    //   @Override

    //   public void run() {

    //     updatePopup();

    //   }

    //}, 500);

    postDelayed(new Runnable() {

      @Override

      public void run() {

        updatePopup();    //

      }

    }, 500);//如果不在post中,而是直接调用,那么弹出位置就会有问题

  }

  虽然上面没有看到对布局的显式调用进行重新布局,照理控件的对象没有被销毁,但是控件在横竖屏切换时应该是需要进行重新layout和measure,然后再进行重绘的,否则不会引发弹出框位置的变化,至于如何调用重新layout、measure和Draw操作,在这里就不多展开了。

自适应横竖屏

如果想让它启动的时候是横屏的话就横屏表示,纵屏的话就纵屏表示,然后手机切换横竖屏就不能用了该怎么解决呢?

首先:在Mainfest.xml中追加

android:screenOrientation="sensor"android:configChanges="orientation|keyboardHidden"这两个属性。

第二步:取得屏幕的长和宽,进行比较设置横竖屏的变量。

  Display display = getWindowManager().getDefaultDisplay();

  int width = display.getWidth();

  int height = display.getHeight();

  if (width > height) {

    orientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;

  } else {

    orientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;

  }

第三步:在onConfigurationChanged()函数中追加this.setRequestedOrientation(orientation)就行了

  @Override

  public void onConfigurationChanged(Configuration newConfig) {

    super.onConfigurationChanged(newConfig);

    this.setRequestedOrientation(mOrientation);

  }

但是这样的话你切到别的画面的时候再回到原画面,它就仍然是横的或者是纵的。怎么让它从别的屏幕回来后,又重新横竖屏布局呢?

只要在OnResume()中在设定下就行了。但是这个只支持横竖屏只有一个layout的。横竖屏分别对应layout的还不知道该怎么解决。

  @Override

  protected void onResume() {

    mOrientation = ActivityInfo.SCREEN_ORIENTATION_USER;

    this.setRequestedOrientation(mOrientation);

    Display display = getWindowManager().getDefaultDisplay();

    int width = display.getWidth();

    int height = display.getHeight();

    if (width > height) {

      mOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;

    } else {

      mOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;

    }

    super.onResume();

  }

另外有需要云服务器可以了解下创新互联scvps.cn,海内外云服务器15元起步,三天无理由+7*72小时售后在线,公司持有idc许可证,提供“云服务器、裸金属服务器、高防服务器、香港服务器、美国服务器、虚拟主机、免备案服务器”等云主机租用服务以及企业上云的综合解决方案,具有“安全稳定、简单易用、服务可用性高、性价比高”等特点与优势,专为企业上云打造定制,能够满足用户丰富、多元化的应用场景需求。


分享标题:Activity横竖屏切换-创新互联
网页路径:http://pwwzsj.com/article/digsee.html