Viewconfiguration和configuration类使用

ViewConfiguration类

ViewConfiguration是系统中关于视图的各种特性的常量记录对象。其中包含各种基础数据,在编写自定义控件时会用经常用到。

下面介绍几个常用的方法:

1.在可滑动的控件中用于区别单击子控件和滑动操作的一个伐值。

mTouchSlop = configuration.getScaledTouchSlop();
   

2.用于设置最小加速率和最大速率.

mMinimumVelocity = configuration.getScaledMinimumFlingVelocity();
mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
   

3.滚动距离

mOverscrollDistance = configuration.getScaledOverscrollDistance();
   

4.fling距离

mOverflingDistance = configuration.getScaledOverflingDistance();
   

5.摩擦力,用来计算减速度

mDeceleration = computeDeceleration(ViewConfiguration.getScrollFriction());
   

ViewConfiguration的常量总结:

/** * 包含了方法和标准的常量用来设置UI的超时、大小和距离 */
 public class ViewConfiguration {     
     // 设定水平滚动条的宽度和垂直滚动条的高度,单位是像素px 
     private static final int SCROLL_BAR_SIZE = 10;     
     //定义滚动条逐渐消失的时间,单位是毫秒 
     private static final int SCROLL_BAR_FADE_DURATION = 250;     
     // 默认的滚动条多少秒之后消失,单位是毫秒 
     private static final int SCROLL_BAR_DEFAULT_DELAY = 300;     
     // 定义边缘地方褪色的长度 
     private static final int FADING_EDGE_LENGTH = 12;     
     //定义子控件按下状态的持续事件 
     private static final int PRESSED_STATE_DURATION = 125;     
     //定义一个按下状态转变成长按状态的转变时间 
     private static final int LONG_PRESS_TIMEOUT = 500;     
     //定义用户在按住适当按钮,弹出全局的对话框的持续时间 
     private static final int GLOBAL_ACTIONS_KEY_TIMEOUT = 500;     
     //定义一个touch事件中是点击事件还是一个滑动事件所需的时间,如果用户在这个时间之内滑动,那么就认为是一个点击事件 
     private static final int TAP_TIMEOUT = 115;     
     /** * Defines the duration in milliseconds we will wait to see if a touch event * is a jump tap. If the user does not complete the jump tap within this interval, it is * considered to be a tap. */
     //定义一个touch事件时候是一个点击事件。如果用户在这个时间内没有完成这个点击,那么就认为是一个点击事件 
     private static final int JUMP_TAP_TIMEOUT = 500;     
     //定义双击事件的间隔时间 
     private static final int DOUBLE_TAP_TIMEOUT = 300;     
     //定义一个缩放控制反馈到用户界面的时间 
     private static final int ZOOM_CONTROLS_TIMEOUT = 3000;     
     /** * Inset in pixels to look for touchable content when the user touches the edge of the screen */
     private static final int EDGE_SLOP = 12;     
     /** * Distance a touch can wander before we think the user is scrolling in pixels */
     private static final int TOUCH_SLOP = 16;     
     /** * Distance a touch can wander before we think the user is attempting a paged scroll * (in dips) */
     private static final int PAGING_TOUCH_SLOP = TOUCH_SLOP * 2;     
     /** * Distance between the first touch and second touch to still be considered a double tap */
     private static final int DOUBLE_TAP_SLOP = 100;     
     /** * Distance a touch needs to be outside of a window's bounds for it to * count as outside for purposes of dismissing the window. */
     private static final int WINDOW_TOUCH_SLOP = 16;     
    //用来初始化fling的最小速度,单位是每秒多少像素 
     private static final int MINIMUM_FLING_VELOCITY = 50;     
     //用来初始化fling的最大速度,单位是每秒多少像素 
     private static final int MAXIMUM_FLING_VELOCITY = 4000;     
     //视图绘图缓存的最大尺寸,以字节表示。在ARGB888格式下,这个尺寸应至少等于屏幕的大小 
     @Deprecated     
     private static final int MAXIMUM_DRAWING_CACHE_SIZE = 320 * 480 * 4; // HVGA screen, ARGB8888 
     //flings和scrolls摩擦力度大小的系数 
     private static float SCROLL_FRICTION = 0.015f;     
     /** * Max distance to over scroll for edge effects */
     private static final int OVERSCROLL_DISTANCE = 0;     
     /** * Max distance to over fling for edge effects */
     private static final int OVERFLING_DISTANCE = 4;     
 }
      

API:14以后提供了方法判断是否有物理按键:ViewConfiguration.hasPermanentMenuKey(). 一般来说物理按键和虚拟按键只会有一种。可以用这个方法来判断是否有导航栏NavigationBar和计算NavigationBar的高度。

判断是否有导航栏NavigationBar:

  public static boolean checkDeviceHasNavigationBar(Context activity) {  
        //通过判断设备是否有返回键、菜单键(不是虚拟键,是手机屏幕外的按键)来确定是否有navigation bar 
        boolean hasMenuKey = ViewConfiguration.get(activity)  
                .hasPermanentMenuKey();  
        boolean hasBackKey = KeyCharacterMap  
                .deviceHasKey(KeyEvent.KEYCODE_BACK);  
        if (!hasMenuKey && !hasBackKey) {  
            // 做任何你需要做的,这个设备有一个导航栏 
            return true;  
        }  
        return false;  
    }  
         

计算NavigationBar的高度:

            public int getNavigationBarHeight(Context c) {
                    int result = 0;
                    boolean hasMenuKey = ViewConfiguration.get(c).hasPermanentMenuKey();
                    boolean hasBackKey = KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_BACK);
                    if (!hasMenuKey && !hasBackKey) {
                        //The device has a navigation bar
                        Resources resources = c.getResources();
                        int orientation = getResources().getConfiguration().orientation;
                        int resourceId;
                        if (isTablet(c)) {
                            resourceId = resources.getIdentifier(orientation == Configuration.ORIENTATION_PORTRAIT ? "navigation_bar_height" : "navigation_bar_height_landscape", "dimen", "android");
                        } else {
                            resourceId = resources.getIdentifier(orientation == Configuration.ORIENTATION_PORTRAIT ? "navigation_bar_height" : "navigation_bar_width", "dimen", "android");
                        }
                        if (resourceId > 0) {
                            return getResources().getDimensionPixelSize(resourceId);
                        }
                    }
                    return result;
                }
    

Configuration类

Configuration类虽然和ViewConfiguration类名字之差一个“view”,但是二者并无继承关系,也没有共同的父类。 Configuration类是专门用来描述手机设备上的配置信息。这些配置信息包括用户特定的配置项,也包括系统的动态设备配置。

程序中可调用Activity的如下方法来获取Configuration对象

//获取系统的Configuration对象
Configuration cfg = getResources().getConfiguration();
      

其中以下的参数代表的配置信息:

  • fontScale:获取当前用户设置的字体的缩放因子。

  • keyboard:获取当前设备所关联的键盘类型。该属性的返回值:KEYBOARD_12KEY(只有12个键的小键盘)、KEYBOARD_NOKEYS、KEYBOARD_QWERTY(普通键盘)

  • keyboardHidden:该属性返回一个boolean值用于标识当前键盘是否可用。该属性不仅会判断系统的硬件键盘,也会判断系统的软键盘(位于屏幕)。

  • locale:获取用户当前的Locale.

  • mcc:获取移动信号的国家码

  • mnc:获取移动信号的网络码

  • navigation:判断系统上方向导航设备的类型。该属性的返回值:NAVIGATION_NONAV(无导航)、NAVIGATION_DPAD(DPAD导航) NAVIGATION_TRACKBALL(轨迹球导航)、NAVIGATION_WHEEL(滚轮导航)

  • orientation:获取系统屏幕的方向。该属性的返回值:ORIENTATION_LANDSCAPE(横向屏幕)、ORIENTATION_PORTRAIT(竖向屏幕)

  • touchscreen:获取系统触摸屏的触摸方式。该属性的返回值:TOUCHSCREEN_NOTOUCH(无触摸屏)、TOUCHSCREEN_STYLUS(触摸笔式触摸屏)、

  • TOUCHSCREEN_FINGER(接收手指的触摸屏)

下面写一个监听屏幕旋转的demo:

MainActivity如下:

    public class MainActivity extends Activity {
        private Button mButton;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            System.out.println("---> onCreate()");
            init();
        }
        private void init(){
            mButton=(Button) findViewById(R.id.button);
            mButton.setOnClickListener(new ClickListenerImpl());
        }
        private class ClickListenerImpl implements View.OnClickListener {
            @Override
            public void onClick(View v) {
                getConfigurationInfo();
            }
        }
        private void getConfigurationInfo(){
            Configuration configuration=getResources().getConfiguration();
            //获取屏幕方向
            int l=configuration.ORIENTATION_LANDSCAPE;
            int p=configuration.ORIENTATION_PORTRAIT;
            if (configuration.orientation==l) {
                System.out.println("现在是横屏");
            }
            if (configuration.orientation==p) {
                System.out.println("现在是竖屏");
            }
            //获取国家码和网络码
            int countryNum=configuration.mcc;
            int netNum=configuration.mnc;
            System.out.println("国家码="+countryNum+",网络码="+netNum);
        }
        @Override
        public void onConfigurationChanged(Configuration newConfig) {
            super.onConfigurationChanged(newConfig);
            System.out.println("---> onConfigurationChanged()");
        }
        @Override
        protected void onSaveInstanceState(Bundle outState) {
            super.onSaveInstanceState(outState);
            outState.putString("name", "mxn");
            outState.putInt("id", 21);
            System.out.println("---> onSaveInstanceState()");
        }
        @Override
        protected void onRestoreInstanceState(Bundle savedInstanceState) {
            super.onRestoreInstanceState(savedInstanceState);
            String name=savedInstanceState.getString("name");
            int id=savedInstanceState.getInt("id");
            System.out.println("---> onRestoreInstanceState()");
            System.out.println("名字="+name+",编号="+id);
        }
    }
    

main.xml如下:

<RelativeLayout
    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"
    >
    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="获取Configuration信息"
        android:textSize="25sp"
        android:layout_marginTop="80dip"
        android:layout_centerHorizontal="true"
        />
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="测试ConfigurationChange"
        android:textSize="25sp"
        android:layout_centerInParent="true"
        />
</RelativeLayout>  
    

AndroidManifest.xml如下:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.mxn.soul.demo" >
    <application
        android:allowBackup="true"
        android:icon="@mipmap/icon"
        android:label="@string/app_name"
        android:name=".BaseApplication"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:configChanges="keyboardHidden|orientation|screenSize"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>
    

1.点击Button利用Configuration查看手机上的配置信息

11-27 11:56:41.763 4093-4093/com.mxn.soul.demo I/System.out: 现在是横屏
11-27 11:56:41.763 4093-4093/com.mxn.soul.demo I/System.out: 国家码=0,网络码=0
    

2.在manifest为Activity配置configChanges时,旋转屏幕,输出如下:

11-27 11:59:26.827 8684-8684/com.mxn.soul.demo I/System.out: ---> onCreate()
11-27 11:59:31.110 8684-8684/com.mxn.soul.demo I/System.out: ---> onConfigurationChanged()
    

由于设备和系统版本的差异,少数情况下设置android:configChanges=”orientation” 无效, 建议设置为:android:configChanges=”keyboardHidden|orientation|screenSize” ,表示当前Activity可以对屏幕是否旋转进行监听 (当然也可对其他系统信息进行监听) 配置后屏幕旋转时会调用onConfigurationChanged()方法.

注意:当onConfigurationChanged发生之后,并不会对activiyt的生命周期有影响的,也就是说当横竖修改之后,android 并不会有任何生命周期的变化。同理还有(键盘显示或者隐藏、用户的语言设置、用户字体修改、对键盘类型修改、键盘导航修改) 这些都可以触发相关的activity的事件产生。

android:configChanges配置说明:

Android通过终止、重启应用程序来重新加载资源文件,以做到对语言、区域和硬件实时变化的支持。它的默认的行为不是总是方便和令人满意的, 尤其当配置变化(如屏幕方向和键盘可视)、用户旋转设备或划出键盘等。你可以通过监测和响应定制你的应用程序来对这些变化作出响应。 为了能让Activity能监听实时的配置变化,需要在manifest节点里添加“android:configChanges”特性,指定你要处理的配置变化事件。 接下来的列表给出了你可以指定的配置变化的事件值:

*orientation 屏幕在纵向和横向间旋转。 *keyboardHidden 键盘显示或隐藏。 *fontScale 用户变更了首选的字体大小。 *locale 用户选择了不同的语言设定。 *keyboard 键盘类型变更,例如手机从12键盘切换到全键盘 *ouchscreen或navigation 键盘或导航方式变化,一般不会发生这样的事件。

你可以选择捕获多个事件,通过在各事件值间使用“|”。 override onConfigurationChanged这个方法去捕获配置变化,通过传入的Configuration 对象的值进行合适的处理。 需要提醒的是需要调用父类的方法super.onConfigurationChanged(newConfig);并且要重新加载Activity使用的资源,以防有变更。

当onConfigurationChanged 被调用时,Activity的资源变量都已经用新的值进行了更新,所以它们是安全的。任何你没有显式指明的配置变化事件, 都将由应用程序捕获,而且仍然会引起应用程序的重启,而不会调用onConfigurationChanged 方法。

3.若不配置android:configChanges,那么每次屏幕旋转的时候都会调用Activity的onCreate()方法 而不会调用onConfigurationChanged()。取消在2中的设置 .此时每次旋转屏幕都会调用onCreate(),并在屏幕旋转前调用onSaveInstanceState()保存现场状态,在选中后调用onRestoreInstanceState() 恢复现场. 所以此时调用顺序为: onSaveInstanceState->onCreate()->onRestoreInstanceState()。除此以外: 当系统内存紧张时可暂时杀死该Activity,内存允许时重启该Activity.在这样情况下也是该调用顺序,原理亦类似.

输出如下:

11-27 12:04:07.508 13914-13914/com.mxn.soul.demo I/System.out: ---> onCreate()
11-27 12:04:11.400 13914-13914/com.mxn.soul.demo I/System.out: ---> onSaveInstanceState()
11-27 12:04:11.464 13914-13914/com.mxn.soul.demo I/System.out: ---> onCreate()
11-27 12:04:11.465 13914-13914/com.mxn.soul.demo I/System.out: ---> onRestoreInstanceState()
11-27 12:04:11.465 13914-13914/com.mxn.soul.demo I/System.out: 名字=mxn,编号=21
    

另外还有一个判断是否是平板的方法如下(官方用法):

  public static boolean isTablet(Context context) {
        return (context.getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_LARGE;
    }
    
    原文作者:mxn原创
    原文地址: http://souly.cn/%E6%8A%80%E6%9C%AF%E5%8D%9A%E6%96%87/2015/11/26/ViewConfiguration%E5%92%8CConfiguration%E7%B1%BB%E4%BD%BF%E7%94%A8/
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞