View的基礎(chǔ)知識

View的概念

View是Android中非常重要的敏沉,它算是Android學(xué)習(xí)體系中比較難啃的一塊骨頭了娜氏,但是用戶與一個app的交互就是與View的交互顽聂,也就是說用戶無時無刻不在與app中的View打交道烙丛,所以把View的知識掌握透徹是一個Android開發(fā)者必要任務(wù)憎账。View所有不在趴捅,基本上一個app里面我們能看見的都是View垫毙,圖片-ImageView、文字-TextView拱绑、列表-ListView/GridView/RecyclerView综芥、按鈕-Button、選擇框-CheckBox猎拨、輸入框-EditText……當(dāng)然還有更重要的一種是自定義View膀藐。除了View,還有ViewGroup红省,比如LinearLayout额各、RelativeLayout、FrameLayout吧恃,它們是可以包含多個ViewGroup或者View的控件虾啦,ViewGroup也繼承了View,也就是說View可以是單個控件,也可以是由多個控件組成的一組控件傲醉。

View的位置參數(shù)

View的位置由它的四個頂點決定针饥,即View的四個屬性:top、left需频、right丁眼、bottom,top表示左上角縱坐標(biāo)昭殉,left表示左上角橫坐標(biāo)苞七,right表示右下角橫坐標(biāo),bottom表示右下角縱坐標(biāo)挪丢。

這些坐標(biāo)都是相對于View的父容器來說的蹂风,所以它是一種相對坐標(biāo)。

View的這四個參數(shù)在源碼中對應(yīng)著mLeft乾蓬、mRight惠啄、mTop和mBottom,獲取的方式直接get任内,比如mLeft=getLeft()撵渡。從Android3.0開始View增加了額外幾個參數(shù),x死嗦、y趋距、translationX、translationY越除,其中x和y是View左上角的坐標(biāo)节腐,而translationX和translationY是View左上角相對于父容器的偏移量,這幾個參數(shù)也是相對于父容器的坐標(biāo)摘盆,且translationX和translationY的初始值是0翼雀,它們也有對應(yīng)的getter/setter方法,這幾個參數(shù)的換算關(guān)系:

x = left + translationX;
y = top + translationY;

View在平移的過程中孩擂,left和top表示的是原始左上角的位置信息狼渊,值不會發(fā)生改變,此時發(fā)生改變的是x肋殴、y囤锉、translationX和translationY。

觸摸事件MotionEvent

在手指接觸屏幕后所產(chǎn)生的一系列事件中护锤,典型的事件類型有以下幾種:

  • ACTION_DOWN 手指剛接觸屏幕時觸發(fā)該事件
  • ACTION_MOVE 手指在屏幕上移動時觸發(fā)該事件
  • ACTION_UP 手指從屏幕抬起時觸發(fā)該事件

當(dāng)手指點擊屏幕滑動一會然后再抬起這一系列動作,屏幕觸發(fā)的事件依次是ACTION_DOWN酿傍、ACTION_MOVE……烙懦、ACTION_UP,只有ACTION_MOVE這個方法會觸發(fā)多次赤炒,其他只會觸發(fā)一次氯析。通過MotionEvent對象我們可以獲取到點擊事件的x和y坐標(biāo)亏较,系統(tǒng)提供了兩組方法:getX/getY和getRaw/getRawY,它們的區(qū)別是:getX/getY返回的是相對于當(dāng)前View左上角的x和y掩缓,而getRaw/getRawY返回的是相對于手機(jī)屏幕左上角的x和y雪情。

TouchSlop

TouchSlop是系統(tǒng)所能識別出的被認(rèn)為是滑動的最小距離,默認(rèn)是8dp你辣,當(dāng)手指在屏幕上滑動時巡通,如果兩次觸發(fā)ACTION_MOVE事件的距離小于TouchSlop這個常量,那么系統(tǒng)就不會認(rèn)為是在進(jìn)行滑動操作舍哄。這個常量和設(shè)備有關(guān)宴凉,獲取該常量的方式如下:

ViewConfiguration.get(getBaseContext()).getScaledTouchSlop();

該常量的意義

當(dāng)我們在處理滑動時,可以利用這個常量來做一些過濾表悬,比如當(dāng)兩次滑動事件的滑動距離小于這個值時我們就可以認(rèn)為未達(dá)到滑動距離的臨界值弥锄,因此可以不認(rèn)為是滑動動作,這樣會有更好的用戶體驗蟆沫。

VelocityTracker

VelocityTracker表示速度追蹤籽暇,用于追蹤手指在滑動過程中的速度,包括水平和垂直方向的速度饭庞,它的使用如下:

在View的onTouchEvent方法中追蹤當(dāng)前單擊事件的速度:

VelocityTracker velocityTracker = VelocityTracker.obtain();
velocityTracker.addMovement(event);
velocityTracker.computeCurrentVelocity(1000);
int xVelocity = (int) velocityTracker.getXVelocity();
int yVelocity = (int) velocityTracker.getYVelocity();

獲取水平方向和豎直方向的速度時图仓,首先要計算速度,即computeCurrentVelocity這個方法必須先調(diào)用但绕,才能接著調(diào)getXVelocity/getYVelocity救崔。computeCurrentVelocity方法的參數(shù)表示的是一個時間單元,單位是ms捏顺。另外這里所說的速度指的是一段時間內(nèi)手指滑過的像素數(shù)六孵,比如講時間設(shè)為1000ms時,表示在1s內(nèi)幅骄,手指在水平方向滑動100像素劫窒,那么水平速度就是100。

速度可以是負(fù)數(shù)拆座,當(dāng)手指從下往上滑動或從右往左滑動時速度就為負(fù)值主巍。
速度 = (終點位置 - 起點位置)/ 時間段

當(dāng)我們最后不需要再使用VelocityTracker時,要記得調(diào)用clear方法來重置并回收內(nèi)存

velocityTracker.clear();
velocityTracker.recycle();

GestureDetector

GestureDetector表示手勢檢測,用于輔助檢測用戶的單擊江场、滑動嘁捷、長按、雙擊等動作搞旭。使用方法如下:

首先創(chuàng)建一個GestureDetector對象并實現(xiàn)GestureDetector.OnGestureListener接口,根據(jù)需要我們還可以實現(xiàn)OnDoubleTapListener接口從而能夠監(jiān)聽雙擊動作。

GestureDetector mGestureDetector = new GestureDetector(getBaseContext(), this);
mGestureDetector.setIsLongpressEnabled(false);

接著接管目標(biāo)View的onTouchEvent方法肄渗,在待監(jiān)聽View的onTouchEvent方法中添加如下代碼:

boolean consume = mGestureDetector.onTouchEvent(event);
return consume;

然后我們就可以有選擇的實現(xiàn)OnGestureListener和OnDoubleTapListener方法中的方法了镇眷。

下面是OnGestureListener接口中的方法:

@Override
public boolean onDown(MotionEvent e) {
    // 手指輕輕觸摸屏幕的一瞬間,由一個ACTION_DOWN觸發(fā)
    return false;
}

@Override
public void onShowPress(MotionEvent e) {
    // 手指輕輕觸摸屏幕翎嫡,尚未松開或拖動欠动,由一個ACTION_DOWN觸發(fā),和onDown的區(qū)別是手指沒有松開或拖動

}

@Override
public boolean onSingleTapUp(MotionEvent e) {
    // 手指輕輕觸摸屏幕后松開惑申,伴隨著一個ACTION_UP觸發(fā)具伍,這是單擊行為
    return false;
}

@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
    // 手指按下屏幕并拖動,有一個ACTION_DOWN和多個ACTION_MOVE觸發(fā)硝桩,這是拖動行為
    return false;
}

@Override
public void onLongPress(MotionEvent e) {
    // 長按事件

}

@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
    // 快速滑動行為沿猜,由一個ACTION_DOWN、多個ACTION_MOVE和一個ACTION_UP觸發(fā)
    return false;
}

下面是OnDoubleTapListener接口中的方法:

@Override
public boolean onSingleTapConfirmed(MotionEvent e) {
    // 嚴(yán)格的單擊行為碗脊,如果觸發(fā)了這個方法啼肩,那么不可能再緊跟著另一個單擊行為,即這只可能是單擊衙伶,而不可能是雙擊中的一次單擊
    return false;
}

@Override
public boolean onDoubleTap(MotionEvent e) {
    // 雙擊祈坠,由兩次連續(xù)的單擊組成,該方法不可能和onSingleTapConfirmed同時觸發(fā)
    return false;
}

@Override
public boolean onDoubleTapEvent(MotionEvent e) {
    // 表示發(fā)生了雙擊行為矢劲,在雙擊的期間赦拘,ACTION_DOWN、ACTION_MOVE芬沉、ACTION_UP都會觸發(fā)這個方法
    return false;
}

實際開發(fā)中躺同,可以不使用GestureDetector,可以自己在View的onTouchEvent方法中實現(xiàn)所需要的監(jiān)聽丸逸,如果是監(jiān)聽滑動相關(guān)的蹋艺,還是自己在onTouchEvent方法中實現(xiàn)比較好,如果是單純的監(jiān)聽某個行為(雙擊黄刚、長按……)捎谨,就使用GestureDetector。

Scroller

彈性滑動對象憔维,用于實現(xiàn)View的彈性滑動涛救,當(dāng)使用View的scrollTo/scrollBy方法來進(jìn)行滑動時,其過程是瞬間完成的业扒,這個沒有過渡效果的滑動用戶體驗不好检吆。這個時候就可以使用Scroller來實現(xiàn)有過渡效果的滑動,其過程不是在一瞬間完成凶赁,而是在一定的時間內(nèi)完成咧栗。Scroller本身無法讓View彈性滑動逆甜,它需要和View的computeScroll方法配合使用才能共同完成這個功能虱肄。關(guān)鍵代碼如下:

mScroller = new Scroller(context);

private void smoothScrollTo(int destX, int destY) {
    int scrollX = getScrollX();
    int delta = destX - scrollX;
    mScroller.startScroll(scrollX, 0, delta, 0, 1000);
    invalidate();
}


@Override
public void computeScroll() {
    if (mScroller.computeScrollOffset()) {
        scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
        postInvalidate();
    }
}

以上就是Android系統(tǒng)中關(guān)于View的幾個重要的基礎(chǔ)知識點致板,不過這也僅僅是View中最基礎(chǔ)的東西,接下來View的滑動咏窿、事件分發(fā)等才是更需要深入理解的知識斟或。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市集嵌,隨后出現(xiàn)的幾起案子萝挤,更是在濱河造成了極大的恐慌,老刑警劉巖根欧,帶你破解...
    沈念sama閱讀 216,919評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件怜珍,死亡現(xiàn)場離奇詭異,居然都是意外死亡凤粗,警方通過查閱死者的電腦和手機(jī)酥泛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,567評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來嫌拣,“玉大人柔袁,你說我怎么就攤上這事∫熘穑” “怎么了捶索?”我有些...
    開封第一講書人閱讀 163,316評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長灰瞻。 經(jīng)常有香客問我腥例,道長,這世上最難降的妖魔是什么酝润? 我笑而不...
    開封第一講書人閱讀 58,294評論 1 292
  • 正文 為了忘掉前任燎竖,我火速辦了婚禮,結(jié)果婚禮上袍祖,老公的妹妹穿的比我還像新娘底瓣。我一直安慰自己,他們只是感情好蕉陋,可當(dāng)我...
    茶點故事閱讀 67,318評論 6 390
  • 文/花漫 我一把揭開白布捐凭。 她就那樣靜靜地躺著,像睡著了一般凳鬓。 火紅的嫁衣襯著肌膚如雪茁肠。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,245評論 1 299
  • 那天缩举,我揣著相機(jī)與錄音垦梆,去河邊找鬼匹颤。 笑死,一個胖子當(dāng)著我的面吹牛托猩,可吹牛的內(nèi)容都是我干的印蓖。 我是一名探鬼主播,決...
    沈念sama閱讀 40,120評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼京腥,長吁一口氣:“原來是場噩夢啊……” “哼赦肃!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起公浪,我...
    開封第一講書人閱讀 38,964評論 0 275
  • 序言:老撾萬榮一對情侶失蹤他宛,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后欠气,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體厅各,經(jīng)...
    沈念sama閱讀 45,376評論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,592評論 2 333
  • 正文 我和宋清朗相戀三年预柒,在試婚紗的時候發(fā)現(xiàn)自己被綠了队塘。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,764評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡卫旱,死狀恐怖人灼,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情顾翼,我是刑警寧澤投放,帶...
    沈念sama閱讀 35,460評論 5 344
  • 正文 年R本政府宣布,位于F島的核電站适贸,受9級特大地震影響灸芳,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜拜姿,卻給世界環(huán)境...
    茶點故事閱讀 41,070評論 3 327
  • 文/蒙蒙 一烙样、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧蕊肥,春花似錦谒获、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,697評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至展东,卻和暖如春赔硫,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背盐肃。 一陣腳步聲響...
    開封第一講書人閱讀 32,846評論 1 269
  • 我被黑心中介騙來泰國打工爪膊, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留权悟,地道東北人。 一個月前我還...
    沈念sama閱讀 47,819評論 2 370
  • 正文 我出身青樓推盛,卻偏偏與公主長得像峦阁,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子小槐,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,665評論 2 354

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