android基礎(chǔ)之自定義view

一、Custom View

1江锨、view的繼承關(guān)系

view繼承關(guān)系.png

2、Android 如何繪制試圖層次

當(dāng)activity獲取焦點(diǎn)時(shí),它必須提供layout層次的根節(jié)點(diǎn),然后android 系統(tǒng)開始視圖的繪制過程。繪制是從layout的根節(jié)點(diǎn)開始的逊朽,按照從上往下的順序,父元素優(yōu)先子元素赊堪。
繪制的兩個(gè)過程:

  • measuring pass:實(shí)現(xiàn)measure(int,int)方法虽画,順序也是從上往下,每個(gè)view保存它自己的測量值
  • layout pass:實(shí)現(xiàn)layout(int,int,int,int)方法合武,順序從上往下,在這個(gè)階段每個(gè)layout manager負(fù)責(zé)他們各自所有子元素的位置竹揍,通過上一步測量的值
    測量和繪制過程是交替進(jìn)行的囱嫩,layout manager可能運(yùn)行 measure pass 若干次吹艇。例如 linearlayout需要支持weight屬性撑教,relativelayout需要測量子節(jié)點(diǎn)多次才能確定約束關(guān)系秆乳。
    view或activity可以再次觸發(fā)測量和繪制過程叶堆。通過 requestLayout()
    在測量和布局計(jì)算完成后畦粮,視圖就開始繪制自己。這個(gè)操作通過invalidate()觸發(fā)。

3宣赔、view 截屏

每個(gè)view都支持創(chuàng)建當(dāng)前顯示狀態(tài)的圖片预麸。

# Build the Drawing Cache
view.buildDrawingCache(); 
 
# Create Bitmap
Bitmap cache = view.getDrawingCache();
 
# Save Bitmap 
saveBitmap(cache);
view.destroyDrawingCache();

二、自定義view

1儒将、創(chuàng)建自定義view

通過繼承view或它的子類师崎,可以創(chuàng)建自定義view
通過onDraw()方法繪制視圖,如果需要重新繪制椅棺,調(diào)用invalidate()觸發(fā)onDraw()
如果定義自己的view,確保參考ViewConfiguration 類,它包含了一些常亮定義

2齐蔽、測量

必須調(diào)用 setMeasuredDimenstion(int,int)設(shè)置結(jié)果

3两疚、定義自定義 layout managers

通過繼承ViewGroup
自定義layout manager 可以重寫 onMeasure() 和 onLayout(),并且計(jì)算孩子元素的測量結(jié)果
測量孩子元素的大小通過measureChildWithMargins();

三、生命周期

一個(gè)視圖會(huì)在它依附到一個(gè)已依附到window的布局結(jié)構(gòu)時(shí)顯示含滴。

  • onAttachedToWindow() 诱渤,當(dāng)window可以時(shí)調(diào)用
  • onDetachedFromWindow(),當(dāng)視圖從父元素中移除時(shí)調(diào)用(父元素必須依附到window)。例如當(dāng)
    activity被回收(finish()方法被調(diào)用)或者視圖在listview中被回收谈况。該方法可以用來停止動(dòng)畫和清理資源

四勺美、定義自定義屬性

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="ColorOptionsView">
        <attr name="titleText" format="string" localization="suggested" />
        <attr name="valueColor" format="color" />
    </declare-styleable>

</resources> 

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
<!-- define new name space for your attributes -->
    xmlns:custom="http://schemas.android.com/apk/res/com.vogella.android.view.compoundview"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
>
<!-- Assume that this is your new component. It uses your new attributes -->
        <com.vogella.android.view.compoundview.ColorOptionsView
            android:layout_width="match_parent"
            android:layout_height="?android:attr/listPreferredItemHeight"
            custom:titleText="Background color"
            custom:valueColor="@android:color/holo_green_light"
             />

</LinearLayout> 

package com.vogella.android.view.compoundview; 
 
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
 
public class ColorOptionsView extends View {
 
  private View mValue;
  private ImageView mImage;
 
  public ColorOptionsView(Context context, AttributeSet attrs) {
    super(context, attrs);
 
    TypedArray a = context.obtainStyledAttributes(attrs,
        R.styleable.Options, 0, 0);
    String titleText = a.getString(R.styleable.Options_titleText);
    int valueColor = a.getColor(R.styleable.Options_valueColor,
        android.R.color.holo_blue_light);
    a.recycle();
 
    // more stuff 
  } 
 
 
}  

對于自定義屬性中的format的值及其含義如下:

format屬性值:reference 、color碑韵、boolean赡茸、dimension、float祝闻、integer占卧、string、fraction联喘、enum华蜒、flag

  1. reference:參考某一資源ID。

    (1)屬性定義:

            <declare-styleable name = "名稱">

                   <attr name = "background" format = "reference" />

            </declare-styleable>
(2)屬性使用:
             <ImageView

                     android:layout_width = "42dip"
                     android:layout_height = "42dip"
                     android:background = "@drawable/圖片ID"

                     />
  1. color:顏色值豁遭。

    (1)屬性定義:

            <declare-styleable name = "名稱">

                   <attr name = "textColor" format = "color" />

            </declare-styleable>
(2)屬性使用:
            <TextView

                     android:layout_width = "42dip"
                     android:layout_height = "42dip"
                     android:textColor = "#00FF00"

                     />
  1. boolean:布爾值叭喜。

    (1)屬性定義:

            <declare-styleable name = "名稱">

                   <attr name = "focusable" format = "boolean" />

            </declare-styleable>
(2)屬性使用:
            <Button
                    android:layout_width = "42dip"
                    android:layout_height = "42dip"
                    android:focusable = "true"
                    />
  1. dimension:尺寸值。

    (1)屬性定義:

            <declare-styleable name = "名稱">

                   <attr name = "layout_width" format = "dimension" />

            </declare-styleable>
(2)屬性使用:
            <Button

                    android:layout_width = "42dip"
                    android:layout_height = "42dip"

                    />
  1. float:浮點(diǎn)值蓖谢。

    (1)屬性定義:

            <declare-styleable name = "AlphaAnimation">

                   <attr name = "fromAlpha" format = "float" />
                   <attr name = "toAlpha" format = "float" />

            </declare-styleable>
(2)屬性使用:
            <alpha
                   android:fromAlpha = "1.0"
                   android:toAlpha = "0.7"

                   />
  1. integer:整型值捂蕴。

    (1)屬性定義:

            <declare-styleable name = "AnimatedRotateDrawable">

                   <attr name = "visible" />
                   <attr name = "frameDuration" format="integer" />
                   <attr name = "framesCount" format="integer" />
                   <attr name = "pivotX" />
                   <attr name = "pivotY" />
                   <attr name = "drawable" />

            </declare-styleable>
(2)屬性使用:
            <animated-rotate

                   xmlns:android = "http://schemas.android.com/apk/res/android" 
                   android:drawable = "@drawable/圖片ID" 
                   android:pivotX = "50%" 
                   android:pivotY = "50%" 
                   android:framesCount = "12" 
                   android:frameDuration = "100"

                   />
  1. string:字符串。

    (1)屬性定義:

            <declare-styleable name = "MapView">
                   <attr name = "apiKey" format = "string" />
            </declare-styleable>
(2)屬性使用:
            <com.google.android.maps.MapView
                    android:layout_width = "fill_parent"
                    android:layout_height = "fill_parent"
                    android:apiKey = "0jOkQ80oD1JL9C6HAja99uGXCRiS2CGjKO_bc_g"

                    />
  1. fraction:百分?jǐn)?shù)闪幽。

    (1)屬性定義:

            <declare-styleable name="RotateDrawable">
                   <attr name = "visible" />
                   <attr name = "fromDegrees" format = "float" />
                   <attr name = "toDegrees" format = "float" />
                   <attr name = "pivotX" format = "fraction" />
                   <attr name = "pivotY" format = "fraction" />
                   <attr name = "drawable" />
            </declare-styleable>
(2)屬性使用:
            <rotate
                   xmlns:android = "http://schemas.android.com/apk/res/android"
               android:interpolator = "@anim/動(dòng)畫ID"
                   android:fromDegrees = "0"
               android:toDegrees = "360"
                   android:pivotX = "200%"
                   android:pivotY = "300%"
               android:duration = "5000"
                   android:repeatMode = "restart"
                   android:repeatCount = "infinite"
                   />
  1. enum:枚舉值启绰。

    (1)屬性定義:

            <declare-styleable name="名稱">
                   <attr name="orientation">
                          <enum name="horizontal" value="0" />
                          <enum name="vertical" value="1" />
                   </attr>           
            </declare-styleable>
(2)屬性使用:
            <LinearLayout
                    xmlns:android = "http://schemas.android.com/apk/res/android"
                    android:orientation = "vertical"
                    android:layout_width = "fill_parent"
                    android:layout_height = "fill_parent">
            </LinearLayout>
  1. flag:位或運(yùn)算。

    (1)屬性定義:

             <declare-styleable name="名稱">
                    <attr name="windowSoftInputMode">
                            <flag name = "stateUnspecified" value = "0" />
                            <flag name = "stateUnchanged" value = "1" />
                            <flag name = "stateHidden" value = "2" />
                            <flag name = "stateAlwaysHidden" value = "3" />
                            <flag name = "stateVisible" value = "4" />
                            <flag name = "stateAlwaysVisible" value = "5" />
                            <flag name = "adjustUnspecified" value = "0x00" />
                            <flag name = "adjustResize" value = "0x10" />
                            <flag name = "adjustPan" value = "0x20" />
                            <flag name = "adjustNothing" value = "0x30" />
                     </attr>        
             </declare-styleable>
 (2)屬性使用:
            <activity
                   android:name = ".StyleAndThemeActivity"
                   android:label = "@string/app_name"
                   android:windowSoftInputMode = "stateUnspecified |stateUnchanged | stateHidden">
                   <intent-filter>
                          <action android:name = "android.intent.action.MAIN" />
                          <category android:name ="android.intent.category.LAUNCHER" />
                   </intent-filter>
             </activity>

特別要注意:

 屬性定義時(shí)可以指定多種類型值沟使。

(1)屬性定義:
            <declare-styleable name = "名稱">

                   <attr name = "background" format = "reference|color" />

            </declare-styleable>
(2)屬性使用:
             <ImageView

                     android:layout_width = "42dip"
                     android:layout_height = "42dip"
                     android:background = "@drawable/圖片ID|#00FF00"

                     />

下面說說AttributeSet與TypedArray在自定義控件中的作用:

AttributeSet的作用就是在控件進(jìn)行初始化的時(shí)候委可,解析布局文件中該控件的屬性(key eg:background)與該值(value eg:@drawable/icon)的信息封裝在AttributeSet中,傳遞給該控件(View)的構(gòu)造函數(shù)。對于非Android自帶的屬性着倾,在View類中處理時(shí)是無法識別的拾酝,因此需要我們自己解析。所以這就要用到另外一個(gè)類TypedArray卡者。在AttributeSet中我們有屬性名稱蒿囤,有屬性值,但是控件如何知道哪個(gè)屬性代表什么意思呢崇决?這個(gè)工作就由TypedArray來做了材诽。TypedArray對象封裝了/values/attrs.xml中的styleable里定義的每個(gè)屬性的類型信息,通過TypedArray我們就可以知道AttributeSet中封裝的值到底是干什么的了恒傻,從而可以對這些數(shù)據(jù)進(jìn)行應(yīng)用脸侥。

AttributeSet就相當(dāng)于一盒糖,TypedArray就相當(dāng)于這盒糖上的標(biāo)簽說明盈厘,告訴用戶每個(gè)糖的口味等睁枕。這盒糖有什么口味是由用戶自己的styleable文件里面的內(nèi)容來決定的。

五沸手、練習(xí)

在 res/values下創(chuàng)建文件attrs.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="Options">
        <attr name="titleText" format="string" localization="suggested" />
        <attr name="valueColor" format="color" />
    </declare-styleable>

</resources> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:custom="http://schemas.android.com/apk/res/com.vogella.android.view.compoundview"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:showDividers="middle"
    android:divider="?android:attr/listDivider"
    tools:context=".MainActivity" >

        <com.vogella.android.view.compoundview.ColorOptionsView
            android:id="@+id/view1"
            android:layout_width="match_parent"
            android:layout_height="?android:attr/listPreferredItemHeight"
            android:background="?android:selectableItemBackground"
            android:onClick="onClicked"
            custom:titleText="Background color"
            custom:valueColor="@android:color/holo_green_light"
             />

        <com.vogella.android.view.compoundview.ColorOptionsView
            android:id="@+id/view2"
            android:layout_width="match_parent"
            android:layout_height="?android:attr/listPreferredItemHeight"
            android:background="?android:selectableItemBackground"
            android:onClick="onClicked"
            custom:titleText="Foreground color"
            custom:valueColor="@android:color/holo_orange_dark"
             />

</LinearLayout> 

創(chuàng)建布局view_color_options.xml

<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android" >

    <TextView
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:layout_centerVertical="true"
      android:layout_marginLeft="16dp"
        android:textSize="18sp" 
        />

  <View
      android:layout_width="26dp"
      android:layout_height="26dp"
      android:layout_centerVertical="true"
      android:layout_marginLeft="16dp"
      android:layout_marginRight="16dp"
      />

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
      android:layout_marginRight="16dp"
        android:layout_centerVertical="true" 
        android:visibility="gone"
        />
     
</merge> 
package com.vogella.android.customview.compoundview; 
 
import com.vogella.android.view.compoundview.R; 
 
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
 
public class ColorOptionsView extends LinearLayout {
 
  private View mValue;
  private ImageView mImage;
 
  public ColorOptionsView(Context context, AttributeSet attrs) {
    super(context, attrs);
 
    TypedArray a = context.obtainStyledAttributes(attrs,
        R.styleable.ColorOptionsView, 0, 0);
    String titleText = a.getString(R.styleable.ColorOptionsView_titleText);
    int valueColor = a.getColor(R.styleable.ColorOptionsView_valueColor,
        android.R.color.holo_blue_light);
    a.recycle();
 
    setOrientation(LinearLayout.HORIZONTAL);
    setGravity(Gravity.CENTER_VERTICAL);
 
    LayoutInflater inflater = (LayoutInflater) context
        .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    inflater.inflate(R.layout.view_color_options, this, true);
 
    TextView title = (TextView) getChildAt(0);
    title.setText(titleText);
 
    mValue = getChildAt(1);
    mValue.setBackgroundColor(valueColor);
 
    mImage = (ImageView) getChildAt(2);
  } 
 
  public ColorOptionsView(Context context) {
    this(context, null);
  } 
 
  public void setValueColor(int color) {
    mValue.setBackgroundColor(color);
  } 
 
  public void setImageVisible(boolean visible) {
    mImage.setVisibility(visible ? View.VISIBLE : View.GONE);
  } 
 
}  

package com.vogella.android.customview.compoundview; 
 
import com.vogella.android.view.compoundview.R; 
 
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;
import android.widget.Toast;
 
public class MainActivity extends Activity {
 
  @Override 
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
  } 
 
  @Override 
  public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present. 
    getMenuInflater().inflate(R.menu.activity_main, menu);
    return true; 
  } 
 
  public void onClicked(View view) {
    String text = view.getId() == R.id.view1 ? "Background" : "Foreground";
    Toast.makeText(this, text, Toast.LENGTH_SHORT).show();
  } 
 
}  

-----------------------華麗的分割線---------------------
最后附上ViewConfiguration 類的源碼

import android.app.AppGlobals;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Point;
import android.os.RemoteException;
import android.provider.Settings;
import android.util.DisplayMetrics;
import android.util.SparseArray;

/**
 * 主要用來獲取一些在UI中所使用到的標(biāo)準(zhǔn)常量外遇,像超時(shí)、尺寸契吉、距離
 */
public class ViewConfiguration {
    /**
     * 定義了水平滾動(dòng)條的寬度和垂直滾動(dòng)條的高度跳仿,單位是dip
     */
    private static final int SCROLL_BAR_SIZE = 10;

    /**
     * 滾動(dòng)條褪去所需要經(jīng)歷的時(shí)間,單位:milliseconds
     */
    private static final int SCROLL_BAR_FADE_DURATION = 250;

    /**
     * 滾動(dòng)條褪去之前的默認(rèn)時(shí)間延遲捐晶,單位:milliseconds
     */
    private static final int SCROLL_BAR_DEFAULT_DELAY = 300;

    /**
     * 定義褪去邊緣的長度塔嬉,單位:dip
     */
    private static final int FADING_EDGE_LENGTH = 12;

    /**
     * 按下狀態(tài)在子控件上的持續(xù)時(shí)間,單位:milliseconds
     */
    private static final int PRESSED_STATE_DURATION = 64;

    /**
     * 定義一個(gè)按下狀態(tài)轉(zhuǎn)變成長按狀態(tài)所需要持續(xù)的時(shí)間租悄,單位:milliseconds
     */
    private static final int DEFAULT_LONG_PRESS_TIMEOUT = 500;

    /**
     * 定義連續(xù)重復(fù)按鍵間的時(shí)間延遲谨究,單位:milliseconds
     */
    private static final int KEY_REPEAT_DELAY = 50;

    /**
     * 如果用戶需要觸發(fā)全局對話框,例如:關(guān)機(jī)泣棋,鎖屏等胶哲,需要按下按鈕所持續(xù)的事件,單位:milliseconds
     */
    private static final int GLOBAL_ACTIONS_KEY_TIMEOUT = 500;

    /**
     * 定義一個(gè)觸摸事件是點(diǎn)擊還是滾動(dòng)的事件間隔潭辈,如果在這個(gè)事件內(nèi)沒有移動(dòng)鸯屿,就認(rèn)為這是一個(gè)點(diǎn)擊,否則就是滾動(dòng)把敢,單位:milliseconds
     */
    private static final int TAP_TIMEOUT = 180;

    /**
     * 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.
     */
    private static final int JUMP_TAP_TIMEOUT = 500;

    /**
     * 定義雙擊的時(shí)間間隔寄摆,如果在這個(gè)時(shí)間內(nèi),就認(rèn)為是雙擊
     */
    private static final int DOUBLE_TAP_TIMEOUT = 300;

    /**
     * 定義雙擊最小的時(shí)間間隔
     */
    private static final int DOUBLE_TAP_MIN_TIME = 40;

    /**
     * 定義一個(gè)觸摸板觸摸到釋放可認(rèn)為是一個(gè)點(diǎn)擊事件而不是一個(gè)觸摸移動(dòng)手勢的最大時(shí)間修赞,
     * 也就是說在這個(gè)時(shí)間內(nèi)進(jìn)行一次觸摸和釋放操作就可以認(rèn)為是一次點(diǎn)擊事件婶恼,單位:milliseconds
     */
    private static final int HOVER_TAP_TIMEOUT = 150;

    /**
     * 定義一個(gè)觸摸板在觸摸釋放之前可以移動(dòng)的最大距離桑阶,
     * 如果在這個(gè)距離之內(nèi)就可以認(rèn)為是一個(gè)點(diǎn)擊事件,否則就是一個(gè)移動(dòng)手勢勾邦,單位:pixels
     */
    private static final int HOVER_TAP_SLOP = 20;

    /**
     * 定義響應(yīng)顯示縮放控制的時(shí)間
     */
    private static final int ZOOM_CONTROLS_TIMEOUT = 3000;

    /**
     * Inset in dips to look for touchable content when the user touches the edge of the screen
     */
    private static final int EDGE_SLOP = 12;

    /**
     * 如果我們認(rèn)為用戶正在滾動(dòng)蚣录,這里定義一個(gè)觸摸事件可以滾動(dòng)的距離,單位:dips
     * 注意:這個(gè)值在這里定義只是作為那些沒有提供上下文Context來決定密度和配置相關(guān)值的應(yīng)用程序的一個(gè)備用值眷篇。
     */
    private static final int TOUCH_SLOP = 8;

    /**
     * 定義雙擊事件之間可以移動(dòng)的距離萎河,單位:dips
     */
    private static final int DOUBLE_TAP_TOUCH_SLOP = TOUCH_SLOP;

    /**
     * 定義用戶嘗試翻頁滾動(dòng)的觸摸移動(dòng)距離,單位:dips
     *
     * 注意:這個(gè)值在這里定義只是作為那些沒有提供上下文Context來決定密度和配置相關(guān)值的應(yīng)用程序的一個(gè)備用值蕉饼。
     *
     */
    private static final int PAGING_TOUCH_SLOP = TOUCH_SLOP * 2;

    /**
     * 定義第一次點(diǎn)擊和第二次點(diǎn)擊可以認(rèn)為是一次雙擊之間的距離虐杯。單位:dips
     */
    private static final int DOUBLE_TAP_SLOP = 100;

    /**
     * Distance in dips 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;

    /**
     * 一個(gè)fling最小的速度,單位:dips/s
     */
    private static final int MINIMUM_FLING_VELOCITY = 50;

    /**
     * 一個(gè)fling最大的速度昧港,單位:dips/s
     */
    private static final int MAXIMUM_FLING_VELOCITY = 8000;

    /**
     * 分發(fā)一個(gè)重復(fù)訪問事件的延遲事件擎椰,單位:milliseconds
     */
    private static final long SEND_RECURRING_ACCESSIBILITY_EVENTS_INTERVAL_MILLIS = 100;

    /**
     * The maximum size of View's drawing cache, expressed in bytes. This size
     * should be at least equal to the size of the screen in ARGB888 format.
     */
    @Deprecated
    private static final int MAXIMUM_DRAWING_CACHE_SIZE = 480 * 800 * 4; // ARGB8888

    /**
     * 滾動(dòng)和滑動(dòng)的摩擦系數(shù)
     */
    private static final float SCROLL_FRICTION = 0.015f;

    /**
     * Max distance in dips to overscroll for edge effects
     */
    private static final int OVERSCROLL_DISTANCE = 0;

    /**
     * Max distance in dips to overfling for edge effects
     */
    private static final int OVERFLING_DISTANCE = 6;

    private final int mEdgeSlop;
    private final int mFadingEdgeLength;
    private final int mMinimumFlingVelocity;
    private final int mMaximumFlingVelocity;
    private final int mScrollbarSize;
    private final int mTouchSlop;
    private final int mDoubleTapTouchSlop;
    private final int mPagingTouchSlop;
    private final int mDoubleTapSlop;
    private final int mWindowTouchSlop;
    private final int mMaximumDrawingCacheSize;
    private final int mOverscrollDistance;
    private final int mOverflingDistance;
    private final boolean mFadingMarqueeEnabled;

    private boolean sHasPermanentMenuKey;
    private boolean sHasPermanentMenuKeySet;

    static final SparseArray<ViewConfiguration> sConfigurations =
            new SparseArray<ViewConfiguration>(2);

    /**
     * 這個(gè)方法被廢除了,使用ViewConfiguration.get(Context)}替代
     */
    @Deprecated
    public ViewConfiguration() {
        mEdgeSlop = EDGE_SLOP;
        mFadingEdgeLength = FADING_EDGE_LENGTH;
        mMinimumFlingVelocity = MINIMUM_FLING_VELOCITY;
        mMaximumFlingVelocity = MAXIMUM_FLING_VELOCITY;
        mScrollbarSize = SCROLL_BAR_SIZE;
        mTouchSlop = TOUCH_SLOP;
        mDoubleTapTouchSlop = DOUBLE_TAP_TOUCH_SLOP;
        mPagingTouchSlop = PAGING_TOUCH_SLOP;
        mDoubleTapSlop = DOUBLE_TAP_SLOP;
        mWindowTouchSlop = WINDOW_TOUCH_SLOP;
        //noinspection deprecation
        mMaximumDrawingCacheSize = MAXIMUM_DRAWING_CACHE_SIZE;
        mOverscrollDistance = OVERSCROLL_DISTANCE;
        mOverflingDistance = OVERFLING_DISTANCE;
        mFadingMarqueeEnabled = true;
    }

    /**
     * 使用給定的context來創(chuàng)建一個(gè)新的配置慨飘。這個(gè)配置依賴于context里面不同的參數(shù),例如顯示的尺寸或者密度
     * @param context 用來初始化這個(gè)view配置的應(yīng)用上下文環(huán)境
     *
     * @see #get(android.content.Context)
     * @see android.util.DisplayMetrics
     */
    private ViewConfiguration(Context context) {
        final Resources res = context.getResources();
        final DisplayMetrics metrics = res.getDisplayMetrics();
        final Configuration config = res.getConfiguration();
        final float density = metrics.density;
        final float sizeAndDensity;
        if (config.isLayoutSizeAtLeast(Configuration.SCREENLAYOUT_SIZE_XLARGE)) {
            sizeAndDensity = density * 1.5f;
        } else {
            sizeAndDensity = density;
        }

        mEdgeSlop = (int) (sizeAndDensity * EDGE_SLOP + 0.5f);
        mFadingEdgeLength = (int) (sizeAndDensity * FADING_EDGE_LENGTH + 0.5f);
        mMinimumFlingVelocity = (int) (density * MINIMUM_FLING_VELOCITY + 0.5f);
        mMaximumFlingVelocity = (int) (density * MAXIMUM_FLING_VELOCITY + 0.5f);
        mScrollbarSize = (int) (density * SCROLL_BAR_SIZE + 0.5f);
        mDoubleTapSlop = (int) (sizeAndDensity * DOUBLE_TAP_SLOP + 0.5f);
        mWindowTouchSlop = (int) (sizeAndDensity * WINDOW_TOUCH_SLOP + 0.5f);

        // Size of the screen in bytes, in ARGB_8888 format
        final WindowManager win = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
        final Display display = win.getDefaultDisplay();
        final Point size = new Point();
        display.getRealSize(size);
        mMaximumDrawingCacheSize = 4 * size.x * size.y;

        mOverscrollDistance = (int) (sizeAndDensity * OVERSCROLL_DISTANCE + 0.5f);
        mOverflingDistance = (int) (sizeAndDensity * OVERFLING_DISTANCE + 0.5f);

        if (!sHasPermanentMenuKeySet) {
            IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
            try {
                sHasPermanentMenuKey = !wm.hasNavigationBar();
                sHasPermanentMenuKeySet = true;
            } catch (RemoteException ex) {
                sHasPermanentMenuKey = false;
            }
        }

        mFadingMarqueeEnabled = res.getBoolean(
                com.android.internal.R.bool.config_ui_enableFadingMarquee);
        mTouchSlop = res.getDimensionPixelSize(
                com.android.internal.R.dimen.config_viewConfigurationTouchSlop);
        mPagingTouchSlop = mTouchSlop * 2;

        mDoubleTapTouchSlop = mTouchSlop;
    }

    /**
     * 跟上面一個(gè)函數(shù)一樣译荞,只不過上面一個(gè)是創(chuàng)建一個(gè)ViewConfiguration對象瓤的,這里是直接通過這個(gè)靜態(tài)方法返回一個(gè)對象
     */
    public static ViewConfiguration get(Context context) {
        final DisplayMetrics metrics = context.getResources().getDisplayMetrics();
        final int density = (int) (100.0f * metrics.density);

        ViewConfiguration configuration = sConfigurations.get(density);
        if (configuration == null) {
            configuration = new ViewConfiguration(context);
            sConfigurations.put(density, configuration);
        }

        return configuration;
    }

    /**
     * @return 獲取水平滾動(dòng)條的寬帶和垂直滾動(dòng)條的高度
     *
     * 這個(gè)函數(shù)被廢除,使用getScaledScrollBarSize()來代替
     */
    @Deprecated
    public static int getScrollBarSize() {
        return SCROLL_BAR_SIZE;
    }

    /**
     * @return 獲取水平滾動(dòng)條的寬帶和垂直滾動(dòng)條的高度
     */
    public int getScaledScrollBarSize() {
        return mScrollbarSize;
    }

    /**
     * @return 滾動(dòng)條褪去的持續(xù)時(shí)間
     */
    public static int getScrollBarFadeDuration() {
        return SCROLL_BAR_FADE_DURATION;
    }

    /**
     * @return 滾動(dòng)條褪去的延遲時(shí)間
     */
    public static int getScrollDefaultDelay() {
        return SCROLL_BAR_DEFAULT_DELAY;
    }

    /**
     * @return 褪去邊緣的長度
     *
     * 這個(gè)方法已經(jīng)廢棄吞歼,用getScaledFadingEdgeLength()替代.
     */
    @Deprecated
    public static int getFadingEdgeLength() {
        return FADING_EDGE_LENGTH;
    }

    /**
     * @return 褪去邊緣的長度圈膏,單位:pixels
     */
    public int getScaledFadingEdgeLength() {
        return mFadingEdgeLength;
    }

    /**
     * @return 在子控件上按住狀態(tài)的持續(xù)時(shí)間
     */
    public static int getPressedStateDuration() {
        return PRESSED_STATE_DURATION;
    }

    /**
     * @return 按住狀態(tài)轉(zhuǎn)變?yōu)殚L按狀態(tài)需要的時(shí)間
     */
    public static int getLongPressTimeout() {
        return AppGlobals.getIntCoreSetting(Settings.Secure.LONG_PRESS_TIMEOUT,
                DEFAULT_LONG_PRESS_TIMEOUT);
    }

    /**
     * @return 重新按鍵時(shí)間
     */
    public static int getKeyRepeatTimeout() {
        return getLongPressTimeout();
    }

    /**
     * @return 重復(fù)按鍵延遲時(shí)間
     */
    public static int getKeyRepeatDelay() {
        return KEY_REPEAT_DELAY;
    }

    /**
     * @return 判斷用戶是單擊還是滾動(dòng)的時(shí)間,在這個(gè)時(shí)間內(nèi)沒有移動(dòng)則是單擊篙骡,否則是滾動(dòng)
     */
    public static int getTapTimeout() {
        return TAP_TIMEOUT;
    }

    /**
     * @return the duration in milliseconds we will wait to see if a touch event
     * is a jump tap. If the user does not move within this interval, it is
     * considered to be a tap.
     */
    public static int getJumpTapTimeout() {
        return JUMP_TAP_TIMEOUT;
    }

    /**
     * @return 得到雙擊間隔時(shí)間稽坤,在這個(gè)時(shí)間內(nèi),則是雙擊糯俗,否則就是單擊
     */
    public static int getDoubleTapTimeout() {
        return DOUBLE_TAP_TIMEOUT;
    }

    /**
     * @return the minimum duration in milliseconds between the first tap's
     * up event and the second tap's down event for an interaction to be considered a
     * double-tap.
     *
     * @hide
     */
    public static int getDoubleTapMinTime() {
        return DOUBLE_TAP_MIN_TIME;
    }

    /**
     * @return the maximum duration in milliseconds between a touch pad
     * touch and release for a given touch to be considered a tap (click) as
     * opposed to a hover movement gesture.
     * @hide
     */
    public static int getHoverTapTimeout() {
        return HOVER_TAP_TIMEOUT;
    }

    /**
     * @return the maximum distance in pixels that a touch pad touch can move
     * before being released for it to be considered a tap (click) as opposed
     * to a hover movement gesture.
     * @hide
     */
    public static int getHoverTapSlop() {
        return HOVER_TAP_SLOP;
    }

    /**
     * @return Inset in dips to look for touchable content when the user touches the edge of the
     *         screen
     *
     * @deprecated Use {@link #getScaledEdgeSlop()} instead.
     */
    @Deprecated
    public static int getEdgeSlop() {
        return EDGE_SLOP;
    }

    /**
     * @return Inset in pixels to look for touchable content when the user touches the edge of the
     *         screen
     */
    public int getScaledEdgeSlop() {
        return mEdgeSlop;
    }

    /**
     * @return Distance in dips a touch can wander before we think the user is scrolling
     *
     * @deprecated Use {@link #getScaledTouchSlop()} instead.
     */
    @Deprecated
    public static int getTouchSlop() {
        return TOUCH_SLOP;
    }

    /**
     * @return Distance in pixels a touch can wander before we think the user is scrolling
     */
    public int getScaledTouchSlop() {
        return mTouchSlop;
    }

    /**
     * @return Distance in pixels the first touch can wander before we do not consider this a
     * potential double tap event
     * @hide
     */
    public int getScaledDoubleTapTouchSlop() {
        return mDoubleTapTouchSlop;
    }

    /**
     * @return Distance in pixels a touch can wander before we think the user is scrolling a full
     * page
     */
    public int getScaledPagingTouchSlop() {
        return mPagingTouchSlop;
    }

    /**
     * @return Distance in dips between the first touch and second touch to still be
     *         considered a double tap
     * @deprecated Use {@link #getScaledDoubleTapSlop()} instead.
     * @hide The only client of this should be GestureDetector, which needs this
     *       for clients that still use its deprecated constructor.
     */
    @Deprecated
    public static int getDoubleTapSlop() {
        return DOUBLE_TAP_SLOP;
    }

    /**
     * @return Distance in pixels between the first touch and second touch to still be
     *         considered a double tap
     */
    public int getScaledDoubleTapSlop() {
        return mDoubleTapSlop;
    }

    /**
     * Interval for dispatching a recurring accessibility event in milliseconds.
     * This interval guarantees that a recurring event will be send at most once
     * during the {@link #getSendRecurringAccessibilityEventsInterval()} time frame.
     *
     * @return The delay in milliseconds.
     *
     * @hide
     */
    public static long getSendRecurringAccessibilityEventsInterval() {
        return SEND_RECURRING_ACCESSIBILITY_EVENTS_INTERVAL_MILLIS;
    }

    /**
     * @return Distance in dips a touch must be outside the bounds of a window for it
     * to be counted as outside the window for purposes of dismissing that
     * window.
     *
     * @deprecated Use {@link #getScaledWindowTouchSlop()} instead.
     */
    @Deprecated
    public static int getWindowTouchSlop() {
        return WINDOW_TOUCH_SLOP;
    }

    /**
     * @return Distance in pixels a touch must be outside the bounds of a window for it
     * to be counted as outside the window for purposes of dismissing that window.
     */
    public int getScaledWindowTouchSlop() {
        return mWindowTouchSlop;
    }

    /**
     * @return Minimum velocity to initiate a fling, as measured in dips per second.
     *
     * @deprecated Use {@link #getScaledMinimumFlingVelocity()} instead.
     */
    @Deprecated
    public static int getMinimumFlingVelocity() {
        return MINIMUM_FLING_VELOCITY;
    }

    /**
     * @return 得到滑動(dòng)的最小速度, 以像素/每秒來進(jìn)行計(jì)算
     */
    public int getScaledMinimumFlingVelocity() {
        return mMinimumFlingVelocity;
    }

    /**
     * @return Maximum velocity to initiate a fling, as measured in dips per second.
     *
     * @deprecated Use {@link #getScaledMaximumFlingVelocity()} instead.
     */
    @Deprecated
    public static int getMaximumFlingVelocity() {
        return MAXIMUM_FLING_VELOCITY;
    }

    /**
     * @return 得到滑動(dòng)的最大速度, 以像素/每秒來進(jìn)行計(jì)算
     */
    public int getScaledMaximumFlingVelocity() {
        return mMaximumFlingVelocity;
    }

    /**
     * The maximum drawing cache size expressed in bytes.
     *
     * @return the maximum size of View's drawing cache expressed in bytes
     *
     * @deprecated Use {@link #getScaledMaximumDrawingCacheSize()} instead.
     */
    @Deprecated
    public static int getMaximumDrawingCacheSize() {
        //noinspection deprecation
        return MAXIMUM_DRAWING_CACHE_SIZE;
    }

    /**
     * The maximum drawing cache size expressed in bytes.
     *
     * @return the maximum size of View's drawing cache expressed in bytes
     */
    public int getScaledMaximumDrawingCacheSize() {
        return mMaximumDrawingCacheSize;
    }

    /**
     * @return The maximum distance a View should overscroll by when showing edge effects (in
     * pixels).
     */
    public int getScaledOverscrollDistance() {
        return mOverscrollDistance;
    }

    /**
     * @return The maximum distance a View should overfling by when showing edge effects (in
     * pixels).
     */
    public int getScaledOverflingDistance() {
        return mOverflingDistance;
    }

    /**
     * The amount of time that the zoom controls should be
     * displayed on the screen expressed in milliseconds.
     *
     * @return the time the zoom controls should be visible expressed
     * in milliseconds.
     */
    public static long getZoomControlsTimeout() {
        return ZOOM_CONTROLS_TIMEOUT;
    }

    /**
     * The amount of time a user needs to press the relevant key to bring up
     * the global actions dialog.
     *
     * @return how long a user needs to press the relevant key to bring up
     *   the global actions dialog.
     */
    public static long getGlobalActionKeyTimeout() {
        return GLOBAL_ACTIONS_KEY_TIMEOUT;
    }

    /**
     * The amount of friction applied to scrolls and flings.
     *
     * @return A scalar dimensionless value representing the coefficient of
     *         friction.
     */
    public static float getScrollFriction() {
        return SCROLL_FRICTION;
    }

    /**
     * Report if the device has a permanent menu key available to the user.
     *
     * <p>As of Android 3.0, devices may not have a permanent menu key available.
     * Apps should use the action bar to present menu options to users.
     * However, there are some apps where the action bar is inappropriate
     * or undesirable. This method may be used to detect if a menu key is present.
     * If not, applications should provide another on-screen affordance to access
     * functionality.
     *
     * @return true if a permanent menu key is present, false otherwise.
     */
    public boolean hasPermanentMenuKey() {
        return sHasPermanentMenuKey;
    }

    /**
     * @hide
     * @return Whether or not marquee should use fading edges.
     */
    public boolean isFadingMarqueeEnabled() {
        return mFadingMarqueeEnabled;
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末尿褪,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子得湘,更是在濱河造成了極大的恐慌杖玲,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,657評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件淘正,死亡現(xiàn)場離奇詭異摆马,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)鸿吆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評論 3 394
  • 文/潘曉璐 我一進(jìn)店門囤采,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人惩淳,你說我怎么就攤上這事蕉毯。” “怎么了?”我有些...
    開封第一講書人閱讀 164,057評論 0 354
  • 文/不壞的土叔 我叫張陵恕刘,是天一觀的道長缤谎。 經(jīng)常有香客問我,道長褐着,這世上最難降的妖魔是什么坷澡? 我笑而不...
    開封第一講書人閱讀 58,509評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮含蓉,結(jié)果婚禮上频敛,老公的妹妹穿的比我還像新娘。我一直安慰自己馅扣,他們只是感情好斟赚,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,562評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著差油,像睡著了一般拗军。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上蓄喇,一...
    開封第一講書人閱讀 51,443評論 1 302
  • 那天发侵,我揣著相機(jī)與錄音,去河邊找鬼妆偏。 笑死刃鳄,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的钱骂。 我是一名探鬼主播叔锐,決...
    沈念sama閱讀 40,251評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼见秽!你這毒婦竟也來了愉烙?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,129評論 0 276
  • 序言:老撾萬榮一對情侶失蹤解取,失蹤者是張志新(化名)和其女友劉穎齿梁,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體肮蛹,經(jīng)...
    沈念sama閱讀 45,561評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡勺择,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,779評論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了伦忠。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片省核。...
    茶點(diǎn)故事閱讀 39,902評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖昆码,靈堂內(nèi)的尸體忽然破棺而出气忠,到底是詐尸還是另有隱情邻储,我是刑警寧澤,帶...
    沈念sama閱讀 35,621評論 5 345
  • 正文 年R本政府宣布旧噪,位于F島的核電站吨娜,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏淘钟。R本人自食惡果不足惜宦赠,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,220評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望米母。 院中可真熱鬧勾扭,春花似錦、人聲如沸铁瞒。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽慧耍。三九已至身辨,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間芍碧,已是汗流浹背煌珊。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留师枣,地道東北人怪瓶。 一個(gè)月前我還...
    沈念sama閱讀 48,025評論 2 370
  • 正文 我出身青樓萧落,卻偏偏與公主長得像践美,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子找岖,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,843評論 2 354

推薦閱讀更多精彩內(nèi)容