3.1 view的基礎知識

1. View的位置參數

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_margin="60px"
    android:background="#aaccccee"
    tools:context="qingfengmy.developmentofart._3view.BaseViewActivity">

    <Button
        android:id="@+id/view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="30px"
        android:text="view" />
</RelativeLayout>
Log.e("aaa", "left=" + view.getLeft() + ",right=" + view.getRight() 
    + ",top=" + view.getTop() + ",bottom=" + view.getBottom());
Log.e("aaa", "x=" + view.getX() + ",y=" + view.getY() + ",translationX=" 
    + view.getTranslationX() + ",translationY=" + view.getTranslationY());
Log.e("aaa","width="+view.getWidth()+",height="+view.getHeight());
 left=30,right=294,top=30,bottom=174
 x=30.0,y=30.0,translationX=0.0,translationY=0.0
 width=264,height=144

換算關系如下:

width=right-left=294-30=264
height=bottom-top=174-30=144
x=left+translationX=30+0=30
y=top+translationY=30+0=30

left,right,top,bottom,x,y都是相對父View的位置桑逝。

2. MotionEvent

@Override
public boolean onTouchEvent(MotionEvent event) {
    switch (event.getAction()){
        case MotionEvent.ACTION_DOWN:
            float x = event.getX();
            float y = event.getY();
            float rawX = event.getRawX();
            float rawY = event.getRawY();
            Log.e("aaa","x="+x+",y="+y+",rawX="+rawX+",rawY="+rawY);
            break;
        case MotionEvent.ACTION_MOVE:
            break;
        case MotionEvent.ACTION_UP:
            break;
        case MotionEvent.ACTION_CANCEL:
            break;
    }
    return super.onTouchEvent(event);
}
x=645.0,y=668.0,rawX=705.0,rawY=968.0

該ViewGroup的margin是60px,可見x,y是相對當前View左上角的x和y坐標,而rawX和rawY返回的是相對于手機屏幕左上角x和y坐標。

x=rawX-60=705-60=645
y方向上除了有60的距離外,還有Toolbar高度和狀態(tài)欄高度。

nexus5的ppi是445锉走,和像素的換算關系是1dp=3px.狀態(tài)欄高度72px.獲得如下:

Rect frame = new Rect();
getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);
int statusBarHeight = frame.top;

Toolbar高度168,獲得如下:

TypedValue tv = new TypedValue();
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.HONEYCOMB){
    if (getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true))
        actionBarHeight = TypedValue.complexToDimensionPixelSize(tv.data,getResources().getDisplayMetrics());
}else if(getTheme().resolveAttribute(R.attr.actionBarSize, tv, true)){
    actionBarHeight = TypedValue.complexToDimensionPixelSize(tv.data,getResources().getDisplayMetrics());
}

那么

y=rawY-actionBarHeight-stateBarHeight-60
    =968-168-72-60=668

3. TouchSlop

TouchSlop是系統(tǒng)所能識別出的被認為是滑動最小距離藕届,小于這個距離的滑動系統(tǒng)不認為是滑動挪蹭。這是個常量,和設備有關休偶,在不同設備上這個值可能不同梁厉,通過如下方式獲得這個常量

int touchSlop = ViewConfiguration.get(this).getScaledTouchSlop();
Log.e("aaa","touchSlop="+touchSlop);

nexus5上這個值是24
看ViewConfiguration的源碼

private static final int TOUCH_SLOP = 8;

這里定義的常量是8,nexus5和px的換算是3倍關系踏兜,所以這里是24.

4. VelocityTracker

速度追蹤词顾,用于追蹤手指在滑動過程中的速度,包括水平和豎直速度碱妆。速度計算如下:

速度=(終點位置-起點位置)/時間段

使用方式如下:

public class BaseViewLayout extends RelativeLayout {
    private VelocityTracker mVelocityTracker;//速度追蹤者

    public BaseViewLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        // 使用VelocityTracker.obtain獲到速度追蹤器
        initVelocityTrackerIfNotExists();
        // 添加追蹤的event
        mVelocityTracker.addMovement(event);
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                // 返回true肉盹,否則后續(xù)的動作接受不到
                return true;
            case MotionEvent.ACTION_MOVE:
                break;
            case MotionEvent.ACTION_UP:
                //1秒內的速度
                mVelocityTracker.computeCurrentVelocity(1000);
                // 獲得速度前要先計算
                int velocityY = (int) mVelocityTracker.getYVelocity();
                int velocityX = (int) mVelocityTracker.getXVelocity();
                Log.e("aaa", "velocityX=" + velocityX + ",velocityY=" + velocityY);
                // 釋放資源
                recycleVelocityTracker();
                break;
            case MotionEvent.ACTION_CANCEL:
                break;
        }
        return super.onTouchEvent(event);
    }

    private void recycleVelocityTracker() {
        if (mVelocityTracker != null) {
            mVelocityTracker.recycle();
            mVelocityTracker = null;
        }
    }

    private void initVelocityTrackerIfNotExists() {
        if (mVelocityTracker == null) {
            mVelocityTracker = VelocityTracker.obtain();
        }
    }
}

5. GestureDetector

手勢檢測器,用于輔助檢測用戶的單擊疹尾,滑動上忍,長按,雙擊等行為航棱。
使用方式如下:

public class GestureViewLayout extends RelativeLayout implements GestureDetector.OnGestureListener {
    GestureDetector gestureDetector = new GestureDetector(getContext(), this);

    public GestureViewLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        // 解決長按屏幕無法拖動的現(xiàn)象
        gestureDetector.setIsLongpressEnabled(false);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        return gestureDetector.onTouchEvent(event);
    }

    // 手指輕輕觸摸屏幕的一瞬間
    @Override
    public boolean onDown(MotionEvent e) {
        return false;
    }

    // 手指輕輕觸摸屏幕睡雇,尚未松開或拖動,和onDown相比饮醇,他強調的是沒有松開或者拖動
    @Override
    public void onShowPress(MotionEvent e) {

    }

    // 單擊
    @Override
    public boolean onSingleTapUp(MotionEvent e) {
        return false;
    }

    // 滾動
    @Override
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
        return false;
    }

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

    }

    // 快速滑動
    @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
        return false;
    }
    
}

6. Scroller

彈性滑動對象,用于實現(xiàn)View的彈性滑動秕豫。用Veiw的scrollTo/scrollBy方法來進行滑動時朴艰,其過程是瞬間完成的观蓄,沒有過度動畫效果。Scroller的過程不是瞬間完成的祠墅,是有動畫效果的侮穿。Scroller本身是無法讓View彈性滑動的,它需要和View的computeScroll方法配合才能共同完成這個功能毁嗦。

public class GestureViewLayout extends RelativeLayout implements GestureDetector.OnGestureListener {
    GestureDetector gestureDetector = new GestureDetector(getContext(), this);

    public GestureViewLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        // 解決長按屏幕無法拖動的現(xiàn)象
        gestureDetector.setIsLongpressEnabled(false);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        return gestureDetector.onTouchEvent(event);
    }

    // 手指輕輕觸摸屏幕的一瞬間亲茅,這里fanhuitrue,下面方法才可以收到
    @Override
    public boolean onDown(MotionEvent e) {
        return true;
    }
    
    // 單擊
    @Override
    public boolean onSingleTapUp(MotionEvent e) {
        int destX = (int) e.getX();
        int destY = (int) e.getY();
        smoothScrollTo(destX, destY);
        return true;
    }

    ...

    Scroller scroller = new Scroller(getContext());

    // 緩慢滾動到指定位置
    private void smoothScrollTo(int destX, int destY) {
        int startX = (int) getX();
        int deltaX = startX - destX;
        int startY = (int) getY();
        int deltaY = startY - destY;
        // 2000ms內滑向目標位置狗准,效果就是慢慢滑動
        // dx,dy的計算是:起始坐標-目標坐標克锣,否則會反向跑
        scroller.startScroll(startX, startY, deltaX, deltaY, 2000);
        invalidate();
    }

    @Override
    public void computeScroll() {
        super.computeScroll();
        if (scroller.computeScrollOffset()) {
            scrollTo(scroller.getCurrX(), scroller.getCurrY());
            postInvalidate();
        }
    }
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市腔长,隨后出現(xiàn)的幾起案子袭祟,更是在濱河造成了極大的恐慌,老刑警劉巖捞附,帶你破解...
    沈念sama閱讀 222,464評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異鸟召,居然都是意外死亡,警方通過查閱死者的電腦和手機欧募,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,033評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來槽片,“玉大人何缓,你說我怎么就攤上這事还栓。” “怎么了剩盒?”我有些...
    開封第一講書人閱讀 169,078評論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長辽聊。 經常有香客問我,道長跟匆,這世上最難降的妖魔是什么异袄? 我笑而不...
    開封第一講書人閱讀 59,979評論 1 299
  • 正文 為了忘掉前任,我火速辦了婚禮玛臂,結果婚禮上烤蜕,老公的妹妹穿的比我還像新娘封孙。我一直安慰自己,他們只是感情好讽营,可當我...
    茶點故事閱讀 69,001評論 6 398
  • 文/花漫 我一把揭開白布虎忌。 她就那樣靜靜地躺著,像睡著了一般橱鹏。 火紅的嫁衣襯著肌膚如雪膜蠢。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,584評論 1 312
  • 那天莉兰,我揣著相機與錄音挑围,去河邊找鬼。 笑死贮勃,一個胖子當著我的面吹牛贪惹,可吹牛的內容都是我干的。 我是一名探鬼主播寂嘉,決...
    沈念sama閱讀 41,085評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼奏瞬,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了泉孩?” 一聲冷哼從身側響起硼端,我...
    開封第一講書人閱讀 40,023評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎寓搬,沒想到半個月后珍昨,有當地人在樹林里發(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 46,555評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡句喷,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,626評論 3 342
  • 正文 我和宋清朗相戀三年镣典,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片唾琼。...
    茶點故事閱讀 40,769評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡兄春,死狀恐怖,靈堂內的尸體忽然破棺而出锡溯,到底是詐尸還是另有隱情赶舆,我是刑警寧澤,帶...
    沈念sama閱讀 36,439評論 5 351
  • 正文 年R本政府宣布祭饭,位于F島的核電站芜茵,受9級特大地震影響,放射性物質發(fā)生泄漏倡蝙。R本人自食惡果不足惜九串,卻給世界環(huán)境...
    茶點故事閱讀 42,115評論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望悠咱。 院中可真熱鬧蒸辆,春花似錦征炼、人聲如沸析既。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,601評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至檐蚜,卻和暖如春沿侈,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背缀拭。 一陣腳步聲響...
    開封第一講書人閱讀 33,702評論 1 274
  • 我被黑心中介騙來泰國打工蛛淋, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人勾效。 一個月前我還...
    沈念sama閱讀 49,191評論 3 378
  • 正文 我出身青樓层宫,卻偏偏與公主長得像,于是被迫代替她去往敵國和親萌腿。 傳聞我的和親對象是個殘疾皇子棠赛,可洞房花燭夜當晚...
    茶點故事閱讀 45,781評論 2 361

推薦閱讀更多精彩內容