最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Android 擴(kuò)大 View 的點(diǎn)擊區(qū)域的方法

 更新時(shí)間:2018年04月08日 09:05:58   作者:huansky  
這篇文章主要介紹了Android 擴(kuò)大 View 的點(diǎn)擊區(qū)域的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧

有時(shí)候,按照視覺(jué)圖做出來(lái)效果后,發(fā)現(xiàn)點(diǎn)擊區(qū)域過(guò)小,不好點(diǎn)擊,用戶體驗(yàn)肯定不好。擴(kuò)大視圖,就會(huì)導(dǎo)致整個(gè)視覺(jué)圖變得不好看。那么有沒(méi)有什么辦法在不改變視圖大小的前提下擴(kuò)大點(diǎn)擊區(qū)域呢?

答案是有!

能夠解決這個(gè)問(wèn)題的前提你要對(duì) View 的事件分發(fā)機(jī)制有一定的了解。

下面我將簡(jiǎn)單介紹一下View 的事件分發(fā)機(jī)制,方便大家理解后面的解決辦法。

為了更清楚的說(shuō)明整個(gè)機(jī)制,采用如下的視圖來(lái)說(shuō)明點(diǎn)擊的事件分發(fā)機(jī)制。下圖是一個(gè) FrameLayout (ViewGroup) 里面包含著一個(gè) ImageView (View)。

先自定義一個(gè) MyFrameLayout,繼承FrameLayout,并實(shí)現(xiàn)兩個(gè)點(diǎn)擊相關(guān)的接口;具體代碼如下:

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);
  }
}

接著,對(duì)于 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");
  }
}

這里要說(shuō)明的是,只有ViewGroup才有 onInterceptTouchEvent 方法的,普通的 View 是沒(méi)有的,它是不能對(duì)事件進(jìn)行攔截的。

那這時(shí)候,如果我們點(diǎn)擊里面的 ImageView,會(huì)有怎樣的輸出呢?結(jié)果如下圖。

那如果點(diǎn)擊外層呢?

0,1,2分別是代表 ACTION_DOWN,ACTION_UP,ACTION_MOVE;從中也可以看出一個(gè)點(diǎn)擊動(dòng)作包含一個(gè)Down,一個(gè)Up,還有多個(gè)Move操作。

再來(lái)看一段源碼:

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

上述的代碼把三者的關(guān)系說(shuō)得很清楚了,對(duì)于一個(gè)對(duì)于一個(gè) ViewGroup 來(lái)說(shuō),點(diǎn)擊事件產(chǎn)生后,首先會(huì)傳遞給它,這時(shí)候會(huì)調(diào)用 dispatchTouchEvent,如果這個(gè) ViewGroup 的 onInterceptTouchEvent 返回 true ,則表示它要攔截該事件,也就會(huì)交給它的 onTouchEvent 來(lái)進(jìn)行處理。如果這個(gè) ViewGroup 的 onInterceptTouchEvent 返回 false 則會(huì)傳給子元素,子元素的 dispatchTouchEvent 就會(huì)被調(diào)用,如此反復(fù)循環(huán)。這與上面一張圖打出的結(jié)果是一致的。

這里還有說(shuō)明的是,如果代碼設(shè)置了 OnTouchListener,那么就會(huì)先調(diào)用 onTouch 方法,然后在調(diào)用 onTouchEvent。OnClickListener 是優(yōu)先級(jí)最低的,所以最后才會(huì)調(diào)用 onClick。

因此,從第二張結(jié)果圖也可以看出,當(dāng)存在 onTouch 之后,onTouchEvent 和 onClick 兩個(gè)方法都不會(huì)在調(diào)用了。

相信到這里,大家對(duì)于View的事件分發(fā)機(jī)制有一定的了解了。

這里回到開(kāi)頭提的那個(gè)問(wèn)題,那么有什么辦法可以擴(kuò)大 View 的點(diǎn)擊區(qū)域呢?

答案:在父 View 設(shè)置 OnTouchListener 對(duì)點(diǎn)擊事件進(jìn)行攔截,通過(guò)判斷點(diǎn)擊的位置,來(lái)決定是相應(yīng)子 View 的事件,還是父 View 的事件。

具體實(shí)現(xiàn)代碼如下:

public class TouchFactory {

  /** 擴(kuò)展垂直方向點(diǎn)擊區(qū)域尺寸 */
  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 對(duì)點(diǎn)擊事件進(jìn)行了封裝,并通過(guò)對(duì)點(diǎn)擊區(qū)域的判斷,來(lái)決定要不要攔截點(diǎn)擊事件。

下面是  MyFrameLayout 的具體實(shí)現(xiàn)。由于是一個(gè)自定義 view, 因此,變量 myImageView 是一定為空的,所以要對(duì)其進(jìn)行賦值。

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;
  }
}

注意事項(xiàng): 當(dāng)對(duì)子 View 設(shè)置 OnClickListener,點(diǎn)擊區(qū)域剛好是子 View 內(nèi)部的時(shí)候,就會(huì)消耗此事見(jiàn),父 View 的攔截處理就無(wú)效了,因此,一旦選擇攔截來(lái)擴(kuò)大點(diǎn)擊區(qū)域,就不要再去子 View 設(shè)置點(diǎn)擊回調(diào)來(lái)消耗點(diǎn)擊事件了。

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

最新評(píng)論

四子王旗| 天峻县| 铁力市| 固镇县| 奎屯市| 宜城市| 大丰市| 定西市| 海淀区| 微博| 泰安市| 长子县| 政和县| 清新县| 崇阳县| 大竹县| 南昌县| 昭通市| 汝阳县| 普宁市| 岳阳市| 扶沟县| 娄底市| 依安县| 临洮县| 射阳县| 慈溪市| 日土县| 辰溪县| 阿鲁科尔沁旗| 阜南县| 沧源| 邓州市| 剑河县| 上饶县| 蒙城县| 扬中市| 北流市| 咸丰县| 湖州市| 宜良县|