软件世界网 购物 网址 三丰软件 | 小说 美女秀 图库大全 游戏 笑话 | 下载 开发知识库 新闻 开发 图片素材
多播视频美女直播
↓电视,电影,美女直播,迅雷资源↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
移动开发 架构设计 编程语言 Web前端 互联网
开发杂谈 系统运维 研发管理 数据库 云计算 Android开发资料
  软件世界网 -> 移动开发 -> 如何做好横屏全屏化交互体验以及其中遇到的坑 -> 正文阅读
移动开发 最新文章
深入了解android中的消息机制Handler
Android
Libgdx之BitmapFont字体
AndroidApp发布到应用市场的流程
Android开发找工作之前先看看这些知识点吧
View的事件分发机制解析
简单介绍了解白鹭引擎Egret
Cocos2d
android获取本地图片(二)
动画特效七:碰撞动画

[移动开发]如何做好横屏全屏化交互体验以及其中遇到的坑

  2016-04-03 20:41:34

前言


最近公司刚起了一个直播项目,我被抽过去参与,负责其中的直播页,在写直播页的过程中,尤其是横屏状态下,用户的交互出现了很大的问题。
问题是:当用户点击EditText控件时,输入法键盘挡住了部分EditText控件。
在解决的过程中,翻阅的大量的文章:
Android 5.0及以上如何在Translucent模式下防止键盘挡住EditText
Android 5.0 如何实现将布局的内容延伸到状态栏实?
关于透明状态栏的使用以及与软键盘冲突的解决办法
android 动态控制状态栏显示和隐藏的方法实例
动态显示和隐藏状态栏
StatusBarUtil
JKeyboardPanelSwitch
虽然,翻阅了这么多文章,但是然并卵,问题并没有得到解决。最后还是在谷歌官方的例子中找到启发。

这篇文章会带你了解的东西


1 让你知道,你到底需要哪种全屏模式。
2 解决全屏模式下(添加透明状态栏情况下),EditText被挡住的问题。

先解决问题(不涉及沉浸式状态栏)


对于视频类项目来说,横屏代表着用户的参与度更高,那么也相应的需要更好的交互体验,一般来说横屏状态下,存在两个View:一个是用于视频播放的View,另一个是用于控制视频状态的控制器View。想要做到完善的交互,对于布局文件来说,还是有一定的格式要求的,请看:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
   >

    <!-- 用于全屏化的View,你可以替代成VideoView, SurfaceView,TextureView等 -->
    <TextView
        android:id="@+id/fullscreen_content"
        android:layout_width="match_parent"
        android:layout_height="200dp"
        android:background="#ff00ff"
        android:gravity="center"
        android:keepScreenOn="true"
        android:text="@string/dummy_content"
        android:textColor="#33b5e5"
        android:textSize="50sp"
        android:textStyle="bold" />

    <!-- 这里是控制器的布局。对于FrameLayout来说,让其使用    android:fitsSystemWindows=true的属性,可以适应系统UI,以保证App的View不被系统UI遮挡。 -->
    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fitsSystemWindows="true">

        <LinearLayout
            android:id="@+id/fullscreen_content_controls"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"           
            android:gravity="bottom"
            android:orientation="vertical">

            <EditText
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:imeOptions="actionDone|flagNoExtractUi" />
        </LinearLayout>
    </FrameLayout>
</FrameLayout>

剩下的就需要代码处理了,既然需要横屏全屏化,你往往会添加如下或者与之类似的代码,以达到全屏化的目的:
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);

但是,千万不要这么做。这个全屏化和我们理想中的全屏化是有差异的,具体差异稍后再说。
为了达到全屏化的目的,我们会监听屏幕旋转事件,当进入横屏模式时, 重新修改需要全屏化View的布局参数(VideoView等),让其宽高等于屏幕的宽高,然后在处理真正的用于全屏化的逻辑。
  @Override
   public void onConfigurationChanged(Configuration newConfig) {
       super.onConfigurationChanged(newConfig);
       if (this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
           hideSystemBar();
           showSystemBarDelay();
           setTranslucentState();
           float height = DensityUtil.getWidthInPx(this);
           float width = DensityUtil.getHeightInPx(this);
           video_player.getLayoutParams().height = (int) height;
           video_player.getLayoutParams().width = (int) width;
       } else if (this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
           showPortraitStateSystemBar();
           clearTranslucentState();
           float width = DensityUtil.getWidthInPx(this);
           float height = getResources().getDimension(R.dimen.super_video_default_height);
           video_player.getLayoutParams().height = (int) height;
           video_player.getLayoutParams().width = (int) width;
       }
   }

其中最核心的代码为:
public void hideSystemBar() {
    int systemUiVisibility = View.SYSTEM_UI_FLAG_LOW_PROFILE | View.SYSTEM_UI_FLAG_FULLSCREEN
            | View.SYSTEM_UI_FLAG_LAYOUT_STABLE
            | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
            | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
    if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) {
        systemUiVisibility |= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
    }
    video_player.setSystemUiVisibility(systemUiVisibility);

    RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) video_player.getLayoutParams();
    layoutParams.topMargin = 0;
    video_player.setLayoutParams(layoutParams);
}

public void showSystemBar() {
    video_player.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
}

只要你按照这种方式处理完,那么横屏状态下EditText控件被遮挡的问题也就随之解决了,即使你加上了透明状态栏想关的代码,EditText也会正常显示。
有兴趣的朋友,可以去在AS上新建一个工程,选择FullScreen的模板,然后自己研究研究。

那么,为什么会这样呢?


首先,我们注意到,在两个关键方法中,都是对被全屏化的View调用了其setSystemUiVisibility(int visibility)方法,通过改变参数,来达到隐藏和显示状态栏的目的。
具体看看这个方法的说明:
public void setSystemUiVisibility(int visibility)
  1. 改变状态栏或者屏幕其他系统UI的可见性。
  2. 允许你App的内容放置在系统操作栏(状态栏)之下,通过平滑的过度效果来隐藏和显示系统UI。
  3. 使用这个方法让用户集中更多的注意力在你应用的内容上。
  4. 典型的使用到这个方法的场景是:杂志阅读器/视频播放器

总结来说:如果你做的是视频播放器,使用这个方法来达到全屏化的目的,比单纯调用getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);这块代码来达到全屏化,得到的交互效果会更加流畅和丝滑。
接下来,我们具体看看这些参数到底什么意思。
在查找资料的过程中,翻看到这篇文章:android 动态控制状态栏显示和隐藏的方法实例
其中博主提到,它使用的方法1没有实现效果的原因在于。调用setSystemUiVisibility()的View不对,并不是随便一个View来调用都能达到全屏化的效果的,必须是被全屏化的那个View来调用才行。
接下来,我们就挨个看看这些常量都是什么意思。
View.SYSTEM_UI_FLAG_LOW_PROFILE
View.SYSTEM_UI_FLAG_FULLSCREEN
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION

View.SYSTEM_UI_FLAG_LOW_PROFILE


请求系统UI进入一个“低调”的模式。在游戏,阅读器,视频播放器等需要“沉浸式”体验的应用中,系统UI常常会让用户分心。在这种模式下,状态栏和导航栏会变暗。

View.SYSTEM_UI_FLAG_FULLSCREEN


请求进入全屏模式,但同时仍然允许用户与系统UI进行交互,这与WindowManager.LayoutParams.FLAG_FULLSCREEN具有相同的视觉效果,一些非关键画面UI(如状态栏)将被隐藏。
但是,WindowManager.LayoutParams.FLAG_FULLSCREEN更强调让用户一直处于一个连续的状态,比如玩游戏。而这个标记则更强调一种沉浸状态,用户可以迅速的退出这种状态。
举个例子,我们看小说的时候,很多时间会专心与小说本身,但是当用户想看一下时间时,点击屏幕,我们可以迅速友好显示系统UI和一些操作控制UI。

View.SYSTEM_UI_FLAG_LAYOUT_STABLE


简单来说,就是防止隐藏和显示系统UI时,控件发生抖动。
如果加上这个设置,无论怎么显示和隐藏系统UI,我们都回到得到一个平滑的过渡效果。
假如你设置了WindowManager.FLAG_FULLSCREEN标记而不是View.SYSTEM_UI_FLAG_FULLSCREE,那么你将得到一直处于隐藏状态的状态栏。注意,改变或清除WindowManager.FLAG_FULLSCREEN不会得到一个平滑的过渡效果。

View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY


其效果是增强显示和隐藏系统UI时的交互体验。
如果不设置的话,那么任何与系统UI的交互,都会导致退出全屏状态。如果设置的话,那么系统UI会短暂的覆盖应用的内容,而且还有一定程度的透明度,并且短暂时间后自动隐藏,并不会退出全屏化。
看一下效果图会更明显一些。
这是全屏化状态

这是设置后的效果。

这是未设置的效果,与系统UI交互直接退出全屏状态。

View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN

View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION


如果窗口有被设置为SYSTEM_UI_FLAG_FULLSCREEN的需求,那么请设置这两个标记,这样可以避免切换系统UI显示与隐藏时,AppUI被覆盖。
如果不设置就会出现下面的情况。

View.SYSTEM_UI_FLAG_HIDE_NAVIGATION


隐藏导航栏
以上都是被全屏化的View所需要进行的处理。对于控制器来说,如果不在布局中设置android:fitsSystemWindows=true属性,那么控制器的UI就会跑到状态栏的下面。

为了避免以上的情况,就不得不解释setFitsSystemWindows(boolean)fitSystemWindows(rect)方法了。
setFitsSystemWindows()方法是设置此视图是否应该考虑系统UI,例如状态栏。并为其留出空间。如果参数为true,代表会为系统UI留出空间,那么fitSystemWindows(rect)会被执行。
fitSystemWindows(rect)方法是,当Window内容的边距发生改变时(进入全屏化),允许调用该方法调正我们App的UI,以适应Window的变化。
正常情况下,系统UI会入侵到AppUI的一些空间(状态栏,输入法,导航栏等),也就是我们App的UI不会出现在系统UI之下。
不过万一你使用了SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION ,你的内容可能会被系统UI覆盖。此时,你能调用这个方法,来确保你的UI不会被系统的UI覆盖。
这个方法的简单实现是使用padding来做到的,并且这个方法默认是不执行的。
其实,在横屏全屏状态下,之所以EditText不会被输入法遮挡,都是由于执行了这个方法。
上一篇文章      下一篇文章      查看所有文章
2016-04-03 20:41:06  
360图书馆 论文大全 母婴/育儿 软件开发资料 网页快照 文字转语音 购物精选 软件 美食菜谱 新闻中心 电影下载 小游戏 Chinese Culture
生肖星座解梦 人民的名义 人民的名义在线看 三沣玩客 拍拍 视频 开发 Android开发 站长 古典小说 网文精选 搜图网 天下美图
中国文化英文 多播视频 装修知识库
2017-4-30 15:02:23
多播视频美女直播
↓电视,电影,美女直播,迅雷资源↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  软件世界网 --