事件滑動衝突和自定義View注意事項

最近狀態一直不是很好,多是由於從年假前就一直在窩裏看資料、寫筆記這種狀態一直持續了大半個月。在這段時間中除了吃喝睡就是看和寫,再加上上班以後又開始了公司項目資料的整理;因此前兩天感受身體的精神狀態有點透支的感受,就休息了一段時間。固然付出和回報都是成正比的,看到《android開發藝術探討》上畫滿了本身的讀書筆記,看到有道筆記和印象筆記中一篇篇文章、看到思惟導圖工具一張張的思惟導圖,內心仍是有不少自豪感。額???上面撤了那麼多有點跑題了。(呵呵)。這篇文章關於事件衝突和自定義view注意事項的筆記,也是複習自定義View的最後一篇了,後面將會複習關於android線程方面的知識。該文章內容主要來自《android開發藝術探討》,在文章最後有這本書的網上版本java

項目源碼

目錄

  • 常見的衝突場景
  • 處理規則
  • 解決方式
  • 自定義的分類
  • 自定義的注意事項
  • 自定義屬性

1. 常見的衝突場景

  • 場景1——外部滑動方向和內部滑動方向不一致
  • 場景2——外部滑動方向和內部滑動方向不一致
  • 場景3——上面兩種狀況的嵌套

2. 處理規則

獲取滑動的方向:android

  • 滑動路徑和水平造成的夾角
  • 水平方向和垂直方向的距離差距
  • 某些特殊狀況可根據水平和垂直方向的速度差

場景1能夠根據滑動方向來解決,場景2和場景3須要根據業務來解決。git

3. 解決方式

一場景1爲例,可使用下面兩種方式解決滑動衝突的問題。github

外部攔截

主要經過父容器的onIterceptTouchEvent()對事件進行攔截canvas

private int mInterceptedX;
private int mInterceptedY;
@Override
public boolean onInterceptHoverEvent(MotionEvent event) {
    boolean intercepted = false;
    int x = (int) event.getX();
    int y = (int) event.getY();

    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            intercepted = false;
            break;
        case MotionEvent.ACTION_MOVE:
            int distanceX = x - mInterceptedX;
            int distanceY = x - mInterceptedY;
            //父容器須要當前點擊事件
            if (Math.abs(distanceX) > Math.abs(distanceY)) {
                intercepted = true;
            } else {
                intercepted = false;
            }
            break;
        case MotionEvent.ACTION_UP:
            intercepted = false;
            break;
    }
    mInterceptedX = x;
    mInterceptedY = y;
    return intercepted;
}
//scroller彈性滑動贊成處理
private void smoothScrollBy(int dx, int dy) {
    mScroller.startScroll(getScrollX(), getScrollY(), dx, dy);
}
@Override
public void computeScroll() {
    super.computeScroll();
    //返回true表明滑動未結束,false表明滑動結束
    if (mScroller.computeScrollOffset()) {
        scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
    }
}
複製代碼

內部攔截

主要是經過自View配合使用requestDisallowInterceptToucthEvent()方法bash

子元素的修改app

private int mLastX;
private int mLastY;
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
    int x = (int) event.getX();
    int y = (int) event.getY();
    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            //子View干預父控件攔截此事件
            getParent().requestDisallowInterceptTouchEvent(true);
            break;
        case MotionEvent.ACTION_MOVE:
            int distanceX = x - mLastX;
            int distanceY = y - mLastY;
            if (Math.abs(distanceX) > Math.abs(distanceY)) {
                //讓父元素繼續攔截所須要的事件
                getParent().requestDisallowInterceptTouchEvent(false);
            }
            break;
        case MotionEvent.ACTION_UP:
            break;
    }
    mLastX = x;
    mLastY = y;
    return super.dispatchTouchEvent(event);
}
複製代碼

父元素的修改ide

@Override
public boolean onInterceptHoverEvent(MotionEvent event) {
    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            return false;
        default:
            return true;
    }
}
複製代碼

4. 自定義的分類

  • 繼承View重寫onDreaw方法
  • 集成ViewGroup派生特殊的layout
  • 集成特定的View(好比TextView)
  • 集成特定的ViewGroup(好比LinearLayout)

5. 自定義的注意事項

  1. 從新定義View的wrap_content測量
  2. 若是有必要,讓view支持padding
  3. 沒有必要在View中使用Handler
  4. View在銷貨的時候記得中止線程和動畫
  5. view有滑動嵌套狀況下要處理好滑動衝突

從新定義wrap_content的測量工具

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);

    int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
    int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
    int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
    int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);

    if (widthSpecMode == MeasureSpec.AT_MOST &&
            heightSpecMode == MeasureSpec.AT_MOST) {
        setMeasuredDimension(200, 200);
    } else if (widthSpecMode == MeasureSpec.AT_MOST) {
        setMeasuredDimension(200, heightSpecSize);
    } else if (heightSpecMode == MeasureSpec.AT_MOST) {
        setMeasuredDimension(widthSpecSize, 200);
    }
}
複製代碼

對padding的支持佈局

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    int paddingLeft = getPaddingLeft();
    int paddingTop = getPaddingTop();
    int paddingRight = getPaddingRight();
    int paddingButton = getPaddingBottom();

    int width = getWidth() - paddingLeft - paddingRight;
    int height = getHeight() - paddingTop - paddingButton;
    int radius = Math.min(width, height);
    canvas.drawCircle(paddingLeft + width / 2,
            paddingTop + height / 2, radius, mPaint);
}
複製代碼

自定義屬性

自定義屬性可分爲三部:

  1. **第一步:**在value目錄中建立自定義屬性的xml文件。好比:cirleview2_attrs.xml
  2. **第二步:**在構造中解析自定義屬性值.
  3. **第三步:**在不居中使用自定義佈局
  • 建立自定義xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="CirleView2">
        <attr name="circleview2_color" format="color" />
    </declare-styleable>
</resources>
複製代碼
  • 在構造中解析自定義屬性值
//獲取自動屬性
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CirleView2);
//入股未設置顏色,默認爲紅色
mColor = typedArray.getColor(R.styleable.CirleView2_circleview2_color, Color.BLUE);
//釋放TypedArray
typedArray.recycle();
複製代碼
  • 在佈局中使用
    • 首先必需要在佈局文件中添加schemas聲明:xmlns:app="http://schemas.android.com/apk/res-auto"。其中app是自定義屬性的前綴,也能夠是其餘名稱。
    • 使用自定義屬性時要加前綴,前綴要和佈局中聲明的一致app:circleview2_color="@android:color/black"
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".customView.Circle2Activity">

    <com.hdd.androidreview.customView.CirleView2
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:circleview2_color="@android:color/black" />
</LinearLayout>
複製代碼

終結

這篇文章沒有加入關於自定ViewGroup對於padding和margin的處理,不過在我之前寫的自定義ViewGroup——FlowLayout中有這方面的處理,若是感興趣能夠去看一看。

參考

《android開發藝術探討》——第4章源碼

相關文章
相關標籤/搜索