国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

Android 擴大 View 的點擊區域的方法

2019-10-22 18:13:11
字體:
來源:轉載
供稿:網友

有時候,按照視覺圖做出來效果后,發現點擊區域過小,不好點擊,用戶體驗肯定不好。擴大視圖,就會導致整個視覺圖變得不好看。那么有沒有什么辦法在不改變視圖大小的前提下擴大點擊區域呢?

答案是有!

能夠解決這個問題的前提你要對 View 的事件分發機制有一定的了解。

下面我將簡單介紹一下View 的事件分發機制,方便大家理解后面的解決辦法。

為了更清楚的說明整個機制,采用如下的視圖來說明點擊的事件分發機制。下圖是一個 FrameLayout (ViewGroup) 里面包含著一個 ImageView (View)。

android,擴大,點擊區域,View

先自定義一個 MyFrameLayout,繼承FrameLayout,并實現兩個點擊相關的接口;具體代碼如下:

public class MyFrameLayout extends FrameLayout implements OnClickListener, OnTouchListener {  private static final String TAG = "Event";  public MyFrameLayout(Context context, AttributeSet attrs) {    super(context, attrs);    Log.d(TAG, "MyFrameLayout init");    setOnClickListener(this);    setOnTouchListener(this);  }  @Override  public boolean dispatchTouchEvent(MotionEvent event) {    Log.d(TAG, "MyFrameLayout dispatchTouchEvent " + event.getAction());    return super.dispatchTouchEvent(event);  }  @Override  public boolean onTouchEvent(MotionEvent event) {    Log.d(TAG, "MyFrameLayout onTouchEvent " + event.getAction() );    return super.onTouchEvent(event);  }  @Override  public void onClick(View view) {    Log.d(TAG, "MyFrameLayout onClick");  }  @Override  public boolean onTouch(View view, MotionEvent event) {    Log.d(TAG, "MyFrameLayout onTouch " + event.getAction());    return true;  }  @Override  public boolean onInterceptTouchEvent(MotionEvent ev) {    Log.d(TAG, "MyFrameLayout onInterceptTouchEvent " + ev.getAction());    return super.onInterceptTouchEvent(ev);  }}

接著,對于 ImageView 也做類似的操作,具體代碼如下:

public class MyImageView extends ImageView implements OnClickListener, OnTouchListener {  private static final String TAG = "Event";  public MyImageView(Context context, AttributeSet attrs) {    super(context, attrs);    Log.d(TAG, "MyImageView init");    setOnClickListener(this);    setOnTouchListener(this);  }  @Override  public boolean dispatchTouchEvent(MotionEvent event) {    Log.d(TAG, "MyImageView dispatchTouchEvent "+ event.getAction());    return super.dispatchTouchEvent(event);  }  @Override  public boolean onTouchEvent(MotionEvent event) {    Log.d(TAG, "MyImageView onTouchEvent "+ event.getAction());    return super.onTouchEvent(event);  }  @Override  public boolean onTouch(View arg0, MotionEvent arg1) {    Log.d(TAG, "MyImageView onTouch " + arg1.getAction());    return false;  }  @Override  public void onClick(View arg0) {    Log.d(TAG, "MyImageView onClick");  }}

這里要說明的是,只有ViewGroup才有 onInterceptTouchEvent 方法的,普通的 View 是沒有的,它是不能對事件進行攔截的。

那這時候,如果我們點擊里面的 ImageView,會有怎樣的輸出呢?結果如下圖。

android,擴大,點擊區域,View

那如果點擊外層呢?

android,擴大,點擊區域,View

0,1,2分別是代表 ACTION_DOWN,ACTION_UP,ACTION_MOVE;從中也可以看出一個點擊動作包含一個Down,一個Up,還有多個Move操作。

再來看一段源碼:

public boolean dispatchTouchEvent(MotionEvent ev){  boolean consume = false;  if(onInterceptTouchEvent(ev)){    consume = onTouchEvent(ev);  } else{    consume = child.dispatchTouchEvent(ev);  }  return consume;}

上述的代碼把三者的關系說得很清楚了,對于一個對于一個 ViewGroup 來說,點擊事件產生后,首先會傳遞給它,這時候會調用 dispatchTouchEvent,如果這個 ViewGroup 的 onInterceptTouchEvent 返回 true ,則表示它要攔截該事件,也就會交給它的 onTouchEvent 來進行處理。如果這個 ViewGroup 的 onInterceptTouchEvent 返回 false 則會傳給子元素,子元素的 dispatchTouchEvent 就會被調用,如此反復循環。這與上面一張圖打出的結果是一致的。

這里還有說明的是,如果代碼設置了 OnTouchListener,那么就會先調用 onTouch 方法,然后在調用 onTouchEvent。OnClickListener 是優先級最低的,所以最后才會調用 onClick。

因此,從第二張結果圖也可以看出,當存在 onTouch 之后,onTouchEvent 和 onClick 兩個方法都不會在調用了。

相信到這里,大家對于View的事件分發機制有一定的了解了。

這里回到開頭提的那個問題,那么有什么辦法可以擴大 View 的點擊區域呢?

答案:在父 View 設置 OnTouchListener 對點擊事件進行攔截,通過判斷點擊的位置,來決定是相應子 View 的事件,還是父 View 的事件。

具體實現代碼如下:

public class TouchFactory {  /** 擴展垂直方向點擊區域尺寸 */  private static final int EXT_V_SIZE = 200;  public static View.OnTouchListener creatTouchListener(){    return new View.OnTouchListener() {      @Override      public boolean onTouch(View v, MotionEvent event) {        if (expendTouchSize(v, event)) {          return true;        }        return false;      }    };  }  public static boolean expendTouchSize(View root, MotionEvent event) {    if (root instanceof MyFrameLayout) {      ImageView view = ((MyFrameLayout) root).getMyImageView();      if (view != null && view.getVisibility() == View.VISIBLE) {        Rect touchRect = new Rect();        view.getGlobalVisibleRect(touchRect);        int action = event.getAction();        float x = event.getRawX();        float y = event.getRawY();        if ((y >= touchRect.top - EXT_V_SIZE) && (y <= touchRect.bottom + EXT_V_SIZE)) {          if (x >= touchRect.left) {            if (action == MotionEvent.ACTION_UP) {              Toast.makeText(view.getContext(), "touch", Toast.LENGTH_SHORT).show();            }            return true;          }        }      }    }    return false;  }}

TouchFactory 對點擊事件進行了封裝,并通過對點擊區域的判斷,來決定要不要攔截點擊事件。

下面是  MyFrameLayout 的具體實現。由于是一個自定義 view, 因此,變量 myImageView 是一定為空的,所以要對其進行賦值。

public class MyFrameLayout extends FrameLayout {  private static final String TAG = "Event";  private MyImageView myImageView;  public MyFrameLayout(Context context) {    this(context, null);  }  public MyFrameLayout(Context context, AttributeSet attrs) {    this(context, attrs, 0);  }  public MyFrameLayout(Context context, AttributeSet attrs, int def) {    super(context, attrs, def);    init();  }  public void init() {    this.setOnTouchListener(TouchFactory.creatTouchListener());  }    public MyImageView getMyImageView() {    if (myImageView == null) {      myImageView = findViewById(R.id.mImage);    }    return myImageView;  }}

注意事項: 當對子 View 設置 OnClickListener,點擊區域剛好是子 View 內部的時候,就會消耗此事見,父 View 的攔截處理就無效了,因此,一旦選擇攔截來擴大點擊區域,就不要再去子 View 設置點擊回調來消耗點擊事件了。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持VEVB武林網。


注:相關教程知識閱讀請移步到Android開發頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 垦利县| 申扎县| 饶河县| 石台县| 涿州市| 虞城县| 西乌| 梓潼县| 行唐县| 丰宁| 南汇区| 淮北市| 微博| 杭锦后旗| 金溪县| 五莲县| 晋中市| 普陀区| 阳江市| 台中市| 炎陵县| 鄄城县| 库车县| 永泰县| 惠东县| 凌海市| 寿光市| 中方县| 普宁市| 汝南县| 北流市| 宁波市| 乐山市| 射阳县| 云安县| 酒泉市| 新余市| 杭锦旗| 文水县| 通海县| 遵义县|