2011-07-13 23 views
27

Tôi có một số chế độ xem mà tôi hiển thị khi nhấn nút. Tôi muốn chúng biến mất nếu tôi nhấp vào bên ngoài các chế độ xem đó.Chế độ xem Android biến mất bằng cách nhấp vào bên ngoài của nó

Điều này sẽ được thực hiện như thế nào trên Android?

Ngoài ra, tôi nhận thấy rằng "nút quay lại" cũng có thể hỗ trợ người dùng Android với điều này - tôi có thể sử dụng đó làm cách thứ hai để đóng chế độ xem - nhưng một số máy tính bảng thậm chí không sử dụng 'vật lý' nút nữa, nó đã được rất nhấn mạnh.

Trả lời

29

An/cách ngu ngốc dễ dàng:

  • Tạo một cái nhìn trống rỗng giả (giả sử ImageView không có nguồn), làm cho nó điền mẹ

  • Nếu nó được nhấp, sau đó làm những gì bạn muốn làm.

Bạn cần có thẻ gốc trong tệp XML của mình để trở thành RelativeLayout. Nó sẽ chứa hai phần tử: view giả của bạn (đặt vị trí của nó là align the Parent Top). Chế độ xem khác là chế độ xem gốc của bạn chứa các chế độ xem và nút (chế độ xem này có thể là LinearLayout hoặc bất kỳ thứ gì bạn tạo ra. Đừng quên đặt vị trí của nó thành align the Parent Top)

Hy vọng điều này sẽ giúp bạn, Chúc may mắn!

+0

LÀM VIỆC THÍCH MỘT CHARM! cảm ơn bạn :) Tôi đã hoài nghi nếu số lần xem hình trống sẽ được nhận dạng – CQM

+11

Bạn có thể chỉ cần sử dụng dạng xem làm chế độ xem giả. Chúng nhẹ hơn một chút và chỉ nhìn thấy nó trong một XML là một lời nhắc nhở tốt rằng nó không được sử dụng như một phần tử trực quan – zienkikk

+0

@RD. Vui mừng khi nghe điều đó :). Tôi đã làm các thủ thuật tương tự như vậy với RelativeLayout. nó là nhiều hơn một bố trí linh hoạt. – iTurki

0

Triển khai onTouchListener(). Kiểm tra rằng các tọa độ của liên lạc nằm ngoài tọa độ của chế độ xem của bạn.

Có thể có một số cách để làm điều đó với onFocus(), v.v. - Nhưng tôi không biết điều đó.

+0

làm cách nào để xác định tọa độ X, Y của chế độ xem của tôi theo kiểu động nào? Tôi có sử dụng pixel hoặc giá trị nhúng mà tôi đã tạo kích thước của nó với – CQM

+0

http://stackoverflow.com/questions/2224844/how-to-get-the-absolute-coordinates-of-a-view – RedLeader

20

Đây là câu hỏi cũ nhưng tôi nghĩ tôi sẽ đưa ra câu trả lời không dựa trên sự kiện onTouch. Như đã được đề xuất bởi RedLeader nó cũng có thể đạt được điều này bằng cách sử dụng các sự kiện trọng tâm. Tôi đã có một trường hợp mà tôi cần để hiển thị và ẩn một loạt các nút được bố trí trong một popup tùy chỉnh, tức là các nút được đặt tất cả trong cùng một ViewGroup. Một số việc bạn cần làm để thực hiện công việc này:

  1. Nhóm xem mà bạn muốn ẩn cần có View.setFocusableInTouchMode(true) được đặt. Điều này cũng có thể được đặt trong XML bằng cách sử dụng android:focusableintouchmode.

  2. bạn xem gốc, tức là thư mục gốc của toàn bộ bố trí của bạn, có lẽ một số loại tuyến tính hoặc diện tương đối, cũng cần để có thể được đặt tiêu điểm theo # 1 trên

  3. Khi nhóm xem được hiển thị bạn gọi View.requestFocus() để tập trung.

  4. nhóm xem bạn cần phải hoặc là ghi đè View.onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) hoặc thực hiện riêng OnFocusChangeListener bạn và sử dụng View.setOnFocusChangeListener()

  5. Khi người dùng chạm bên ngoài tầm nhìn của bạn tập trung được chuyển giao cho một trong hai gốc view (kể từ khi bạn thiết lập nó như thể đặt tiêu điểm trong # 2) hoặc đến một chế độ xem khác vốn có thể lấy nét (EditText hoặc tương tự)

  6. Khi bạn phát hiện mất tiêu điểm bằng một trong các phương pháp trong # 4 bạn biết rằng tiêu điểm đã được chuyển sang thứ gì đó bên ngoài nhóm xem của bạn và bạn có thể ẩn nó.

Tôi đoán giải pháp này không hoạt động trong mọi trường hợp, nhưng nó hoạt động trong trường hợp cụ thể của tôi và có vẻ như nó có thể hoạt động cho OP.

+1

đề xuất nhỏ: setFocusableInTouchMode đảm bảo setFocusable cũng được đặt. – Edison

+0

Bạn nói đúng, tôi không đọc tài liệu đúng cách. Tôi sẽ cập nhật câu trả lời. – britzl

8

Tôi đã tìm cách đóng chế độ xem của mình khi chạm vào bên ngoài và không có phương pháp nào trong số này phù hợp với nhu cầu của tôi thực sự tốt. Tôi đã tìm thấy một giải pháp và sẽ chỉ đăng nó ở đây trong trường hợp ai đó quan tâm.

Tôi có một hoạt động cơ sở có khá nhiều hoạt động của mình mở rộng. Trong đó tôi có:

@Override 
public boolean dispatchTouchEvent(MotionEvent ev) { 
    if (myViewIsVisible()){ 
      closeMyView(); 
     return true; 
    } 
    return super.dispatchTouchEvent(ev); 
} 

Vì vậy, nếu nhìn thấy nó sẽ chỉ đóng lại, và nếu không nó sẽ hoạt động như một sự kiện cảm ứng bình thường. Bạn không chắc đó có phải là cách tốt nhất để làm điều đó hay không, nhưng nó có vẻ hiệu quả với tôi.

+5

điều gì xảy ra khi chế độ xem của bạn hiển thị và bạn nhấp vào nó? có vẻ như nó sẽ đóng nó anyway – Guillaume

+0

Rất hữu ích. Xem phần sau để có thể xác định xem chạm có ở trong chế độ xem sẽ biến mất khi nhấp chuột ở bên ngoài nó không: http://stackoverflow.com/questions/20700286/how-to-detect-a-motionevent-inside- dispatchtouchevent [link] – dazed

+0

Tôi với @Guillaume, điều này có thực sự vô dụng vì bạn không bao giờ có thể nhấp vào chế độ xem của mình? – behelit

2

Tôi cần khả năng cụ thể để không chỉ xóa chế độ xem khi nhấp vào bên ngoài, mà còn cho phép nhấp để chuyển sang hoạt động bình thường. Ví dụ: tôi có bố cục riêng, notification_bar.xml, mà tôi cần phải tăng động và thêm vào bất kỳ hoạt động hiện tại nào khi cần.

Nếu tôi tạo chế độ xem lớp phủ kích thước màn hình để nhận bất kỳ nhấp chuột nào bên ngoài chế độ xem thông báo và xóa cả hai chế độ xem này khi nhấp chuột, chế độ xem gốc (chế độ xem chính của hoạt động) vẫn chưa nhận được bất kỳ nhấp chuột nào , có nghĩa là khi notification_bar hiển thị, phải mất hai lần nhấp chuột để nhấp vào nút (một nút để loại bỏ chế độ xem notification_bar và một lần nhấp vào nút).

Để giải quyết điều này, bạn chỉ có thể tạo DismissViewGroup của riêng bạn mà kéo dài ViewGroup và override phương thức sau đây:

@Override 
public boolean onInterceptTouchEvent(MotionEvent ev) { 
    ViewParent parent = getParent(); 
    if(parent != null && parent instanceof ViewGroup) { 
     ((ViewGroup) parent).removeView(this); 
    } 
    return super.onInterceptTouchEvent(ev); 
} 

Và sau đó xem động thêm bạn sẽ nhìn một chút như:

<com.example.DismissViewGroup android:id="@+id/touch_interceptor_view" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:background="@android:color/transparent" ... 
    <LinearLayout android:id="@+id/notification_bar_view" ... 

Điều này sẽ cho phép bạn tương tác với chế độ xem và thời điểm bạn nhấp vào bên ngoài chế độ xem, cả hai loại bỏ chế độ xem và tương tác bình thường với hoạt động.

16

Tìm hình chữ nhật chế độ xem và sau đó phát hiện xem sự kiện nhấp có ở bên ngoài chế độ xem hay không.

@Override 
public boolean dispatchTouchEvent(MotionEvent ev) { 
    Rect viewRect = new Rect(); 
    mTooltip.getGlobalVisibleRect(viewRect); 
    if (!viewRect.contains((int) ev.getRawX(), (int) ev.getRawY())) { 
     setVisibility(View.GONE); 
    } 
    return true; 
} 

Nếu bạn muốn sử dụng các sự kiện liên lạc nơi nào khác, hãy thử

return super.dispatchTouchEvent(ev); 
+2

Chỉ cần lưu ý, 'dispatchTouchEvent()' có nghĩa vụ trả về một boolean, nhưng bạn không trả lại bất cứ điều gì trong ví dụ của bạn. Ngoài ra, bạn không xác định hoặc giải thích 'viewRect' là gì. – CaptJak

+0

Cảm ơn bạn, CaptJak. –

+0

Điều này hoạt động thực sự tốt và dễ thực hiện. – behelit

0

Tôi đã tạo custom ViewGroup để hiển thị hộp thông tin neo vào một view (cửa sổ bật lên khinh khí cầu). Chế độ xem con là hộp thông tin thực tế, BalloonView là chế độ toàn màn hình để xác định vị trí tuyệt đối của trẻ và chặn liên lạc.

public BalloonView(View anchor, View child) { 
    super(anchor.getContext()); 
    //calculate popup position relative to anchor and do stuff 
    init(...); 
    //receive child via constructor, or inflate/create default one 
    this.child = child; 
    //this.child = inflate(...); 
    //this.child = new SomeView(anchor.getContext()); 
    addView(child); 
    //this way I don't need to create intermediate ViewGroup to hold my View 
    //but it is fullscreen (good for dialogs and absolute positioning) 
    //if you need relative positioning, see @iturki answer above 
    ((ViewGroup) anchor.getRootView()).addView(this); 
} 

private void dismiss() { 
    ((ViewGroup) getParent()).removeView(this); 
} 

Xử lý nhấp chuột bên trong con:

child.setOnClickListener(new View.OnClickListener() { 
    @Override 
    public void onClick(View v) { 
     //write your code here to handle clicks inside 
    } 
}); 

Để bỏ Xem của tôi bằng cách nhấp chuột bên ngoài KHÔNG ủy cảm ứng để Xem bên dưới:

BalloonView.this.setOnClickListener(new View.OnClickListener() { 
    @Override 
    public void onClick(View v) { 
     dismiss(); 
    } 
}); 

Để bỏ Xem của tôi bằng cách nhấp chuột bên ngoài VỚI ủy lạc để xem bên dưới:

@Override 
public boolean onTouchEvent(MotionEvent event) { 
    dismiss(); 
    return false; //allows underlying View to handle touch 
} 

Để sa thải vào nút Back ép:

//do this in constructor to be able to intercept key 
setFocusableInTouchMode(true); 
requestFocus(); 

@Override 
public boolean onKeyPreIme(int keyCode, KeyEvent event) { 
    if (keyCode == KeyEvent.KEYCODE_BACK) { 
     dismiss(); 
     return true; 
    } 
    return super.onKeyPreIme(keyCode, event); 
} 
-1

cảm ơn @ituki cho ý tưởng

FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" 
android:id="@+id/search_container" 
android:layout_width="match_parent" 
android:layout_height="match_parent" 
android:background="#80000000" 
android:clickable="true"> 

<LinearLayout 
    android:clickable="true" // not trigger 
    android:layout_width="match_parent" 
    android:layout_height="300dp" 
    android:background="#FFF" 
    android:orientation="vertical" 
    android:padding="20dp"> 

    ............... 

</LinearLayout> 
</FrameLayout> 

và mã java

mContainer = (View) view.findViewById(R.id.search_container); 
    mContainer.setOnTouchListener(new View.OnTouchListener() { 
     @Override 
     public boolean onTouch(View v, MotionEvent event) { 
      if(event.getAction() == MotionEvent.ACTION_DOWN){ 
       Log.d("aaaaa", "outsite"); 
       return true; 
      } 
      return false; 
     } 
    }); 

nó làm việc khi liên lạc bên ngoài LinearLayout

Các vấn đề liên quan