Android 캡 처 이벤트 범위 클릭 방법

View 의 Tween 애니메이션 과정 에서 이벤트 의 위 치 를 클릭 하 는 것 은 애니메이션 의 위치 가 바 뀌 지 않 습 니 다.애니메이션 과정 에서 layot 의 위치 가 실제 적 으로 바 뀌 지 않 았 기 때문에 View 의 클릭 이벤트(사실은 클릭 이벤트 뿐만 아니 라 모든 터치 이벤트 포함)가 촉발 하 는 범 위 는 이 View 가 layot 에서 지정 한 left,top,right 라 고 생각 했 습 니 다.bottom。오늘 에 야 완전히 그렇지 는 않다 는 것 을 알 게 되 었 다.모든 것 은 평소에 코드 를 자세히 보지 않 아서 문제 에 대한 이해 가 전면적 이지 못 하기 때문이다.
여기 서 문 제 를 발견 하고 문 제 를 처리 하 는 과정 을 기록 해 보 세 요.

이러한 ViewGroup,layot 두 개의 선형 레이아웃 을 사용자 정의 합 니 다.왼쪽 LinearLayout 는 전체 화면 을 덮어 쓰 고 오른쪽 LinearLayout 는 화면 밖 에 숨 깁 니 다.그 다음 에 미 끄 러 지 려 는 과정 에서 두 번 째 LinearLayout 가 나타 나 는 과정 에서 버튼 버튼 버튼 과 두 번 째 선형 구조의 위치 정 보 를 관찰 합 니 다.

왼쪽 으로 두 번 째 선형 천 을 미 끄 러 뜨리 는 과정 에서 그의 위 치 는 변 하지 않 았 음 을 알 수 있다.여기 서 getLeft(),getTop(),getRight(),getBottom()을 통 해 얻 은 위 치 를 말한다.즉,layot 가 결정 하 는 위 치 를 말한다.
위치 가 바 뀌 지 않 았 으 니 이 럴 때 두 번 째 선형 레이아웃 과 단 추 를 누 르 면 이벤트 가 응답 합 니 다.이 는 이벤트 의 위 치 를 캡 처 하 는 것 이 layot 의 위치 가 아니 라 는 것 을 의미 합 니 다.화면 밖으로 손 을 내밀 고 클릭 하지 않 았 기 때문에...
ViewGroup\#dispatchTouchEvent 방법 을 돌 이 켜 보면 터치 이 벤트 를 나 눠 줄 때:

for (int i = count - 1; i >= 0; i--) { 
 final View child = children[i]; 
 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE 
   || child.getAnimation() != null) { 
  child.getHitRect(frame); 
  if (frame.contains(scrolledXInt, scrolledYInt)) { 
   // offset the event to the view's coordinate system 
   final float xc = scrolledXFloat - child.mLeft; 
   final float yc = scrolledYFloat - child.mTop; 
   ev.setLocation(xc, yc); 
   child.mPrivateFlags &= ~CANCEL_NEXT_UP_EVENT; 
   if (child.dispatchTouchEvent(ev)) { 
    // Event handled, we have a target now. 
    mMotionTarget = child; 
    return true; 
   } 
  } 
} 
그 중에서 frame.contains(scrolledXInt,scrolledYInt)함 수 는 바로 판단 점(scrolledXInt,scrolledYInt)이 frame 사각형 안에 있 는 지 아 닌 지 를 판단 하 는 것 입 니 다.이 직사각형 frame 은 child.getHitRect(frame)입 니 다.획득:

public void getHitRect(Rect outRect) { 
  outRect.set(mLeft, mTop, mRight, mBottom); 
} 
분명히 이 사각형 은 이 하위 View 의 Layout 레이아웃 매개 변수 에 의 해 결정 된다.그러나 scrolledXInt 와 scrolledYInt 인 자 는 우리 가 손가락 으로 클릭 한 위치 가 아 닙 니 다.

final int action = ev.getAction(); 
final float xf = ev.getX(); 
final float yf = ev.getY(); 
final float scrolledXFloat = xf + mScrollX; 
final float scrolledYFloat = yf + mScrollY; 
…… 
final int scrolledXInt = (int) scrolledXFloat; 
final int scrolledYInt = (int) scrolledYFloat; 
이 점 이 하위 뷰 에 포함 되 어 있 는 지 판단 할 때 이 점 은 손가락 이 클릭 한 좌표 가 아니 라 손가락 이 클릭 한 좌표 에 mScrollX 와 mScrolly 를 더 한 다음 에 이 하위 뷰 의 범위 안에 있 는 지 판단 하 는 것 을 알 수 있다.
현재 왼쪽으로 미 끄 러 지 는 과정 에서 두 번 째 선형 구조의 위 치 는 변 하지 않 았 지만 layot 의 매개 변수 위 치 는 mLeft:720,mTop:0,mRight:1440,mBottom:1134 이다.
그러나 그의 아버지 View 의 mScrollX 가 바 뀌 었 다.왼쪽으로 미 끄 러 지 는 mScrollX 는 0 보다 크다.이것 은 손 으로 두 번 째 선형 구 조 를 클릭 하고 손 이 클릭 한 위치 에 mScrollX 의 값 을 더 하면 두 번 째 선형 구조의 layot 범위 에 떨어진다.
 테스트 코드:
사용자 정의 MyViewGroup:

public class MyViewGroup extends ViewGroup { 
 
 public static final String TAG = "MyViewGroup"; 
 private int childCount; 
 private GestureDetector detector; 
 private Button btn; 
 private LinearLayout ll2; 
 public MyViewGroup(Context context, AttributeSet attrs, int defStyle) { 
  super(context, attrs, defStyle); 
  init(context); 
 } 
 
 public MyViewGroup(Context context, AttributeSet attrs) { 
  super(context, attrs); 
  init(context); 
 } 
 
 public MyViewGroup(Context context) { 
  super(context); 
  init(context); 
 } 
 
 private void init(final Context context) { 
  detector = new GestureDetector(context, new MyOnGestureListener()); 
  LinearLayout ll1 = new LinearLayout(context); 
  ll1.setBackgroundColor(Color.BLUE); 
  ll2 = new LinearLayout(context); 
  ll2.setBackgroundColor(Color.RED); 
  btn = new Button(context); 
  btn.setText("    "); 
  ll2.addView(btn); 
  addView(ll1); 
  addView(ll2); 
 
  setOnTouchListener(new MyTouchEvent()); 
  ll2.setOnClickListener(new OnClickListener() { 
    
   @Override 
   public void onClick(View v) { 
    Toast.makeText(context, "       2", 0).show(); 
     
   } 
  }); 
  btn.setOnClickListener(new OnClickListener() { 
    
   @Override 
   public void onClick(View v) { 
    Toast.makeText(context, "   Button", 0).show(); 
   } 
  }); 
 } 
 
 @Override 
 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 
  super.onMeasure(widthMeasureSpec, heightMeasureSpec); 
  childCount = getChildCount(); 
  for (int i = 0; i < childCount; i++) { 
   View child = getChildAt(i); 
   child.measure(widthMeasureSpec,heightMeasureSpec); 
  } 
 } 
  
 @Override 
 protected void onLayout(boolean changed, int l, int t, int r, int b) { 
 
  for (int i = 0; i < childCount; i++) { 
   View child = getChildAt(i); 
   child.layout(0+i*getWidth(), 0, (i+1)*getWidth(), getHeight()); 
  } 
 } 
 
 private class MyTouchEvent implements View.OnTouchListener{ 
 
  @Override 
  public boolean onTouch(View v, MotionEvent event) { 
    
   detector.onTouchEvent(event); 
   return true; 
  } 
   
 } 
  
 private class MyOnGestureListener extends SimpleOnGestureListener{ 
  @Override 
  public boolean onScroll(MotionEvent e1, MotionEvent e2, 
    float distanceX, float distanceY) { 
   scrollBy((int) distanceX, 0); 
    
   if (getScrollX()% 10 == 0) {     
    Log.i(TAG, "Button      :" + btn.getLeft() + "/" 
      + btn.getTop() + "/" 
      + btn.getRight() + "/" 
      + btn.getBottom()); 
    Log.i(TAG, "    2       :" + ll2.getLeft() + "/" 
      + ll2.getTop() + "/" 
      + ll2.getRight() + "/" 
      + ll2.getBottom()); 
    Log.i(TAG, "MyViewGroup mScrollX:" + getScrollX()); 
   } 
   return super.onScroll(e1, e2, distanceX, distanceY); 
  } 
 } 
} 
그리고 Activity 에서:

public class MainActivity extends Activity { 
 
 @Override 
 protected void onCreate(Bundle savedInstanceState) { 
  super.onCreate(savedInstanceState); 
  setContentView(new MyViewGroup(this)); 
 } 
}
이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.

좋은 웹페이지 즐겨찾기