2011-07-13 75 views
27

我有一些視圖可以在按下按鈕時看到。如果我在這些視圖之外點擊,我希望它們消失。Android讓視圖通過點擊消失而消失

這將如何在Android上完成?另外,我意識到「後退按鈕」也可以幫助Android用戶 - 我可以使用它作爲關閉視圖的輔助方式 - 但某些平板電腦甚至不使用「物理」背面按鈕,它已被非常強調。

回答

29

一個簡單/笨的辦法:

  • 創建一個虛擬空視圖(假設沒有源ImageView的),使其填補父

  • 如果它被點擊,然後做你想做的去做。

您需要將XML文件中的根標記設置爲RelativeLayout。它將包含兩個元素:您的虛擬視圖(將其位置設置爲align the Parent Top)。另一個是包含視圖和按鈕的原始視圖(此視圖可能是LinearLayout或任何您製作的視頻,不要忘記將其位置設置爲align the Parent Top

希望這會對您有所幫助,祝您好運!

+0

工作就像一個魅力!謝謝:)如果空白圖像被識別,我會懷疑 – CQM

+11

您可以簡單地使用視圖作爲虛擬視圖。它們稍微輕一點,只要在XML中看到它就是一個很好的提示,它不被用作視覺元素 – zienkikk

+0

@RD。很高興聽你這樣說 :) 。我用RelativeLayout做了類似於這個的技巧。它不僅僅是一個靈活的佈局。 – iTurki

0

實施onTouchListener()。檢查觸摸的座標是否在視圖的座標之外。

可能有某種方法可以通過onFocus()等來實現 - 但我不知道它。

+0

我該怎麼辦確定我的視圖的X,Y座標是動態的嗎?我是否使用像素或傾斜值,我創建它的大小與 – CQM

+0

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

20

這是一個老問題,但我想我會給出一個不基於onTouch事件的答案。正如RedLeader所建議的那樣,使用焦點事件也可以實現這一點。我有一個例子,我需要顯示和隱藏排列在自定義彈出窗口中的一堆按鈕,即按鈕全部放置在相同的ViewGroup中。你需要做一些事情,使這項工作:

  1. ,你要隱藏的需求有View.setFocusableInTouchMode(true)設置視圖組。這也可以使用android:focusableintouchmode以XML格式設置。

  2. 您的視圖根,即你的整個佈局的根,可能某種線性或相對佈局的,也需要能夠成爲焦點按照#1以上

  3. 當顯示視圖組你打電話View.requestFocus()給它重點。

  4. 你的視圖組需要或者重寫View.onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect)或實現自己的OnFocusChangeListener和使用View.setOnFocusChangeListener()

  5. 當用戶點擊您的視野之外的焦點轉移到任何視圖根(因爲你設置它在#作爲可聚焦2)或另一個本質上可以聚焦的視圖EditText或其他類似

  6. 當您使用#4中的某種方法檢測到焦點丟失時,您知道焦點已轉移到您的視圖組之外,您可以隱藏它。

我想這個解決方案並不適用於所有情況,但它在我的具體情況下工作,聽起來好像它也可以用於OP。

+1

小建議:setFocusableInTouchMode確保setFocusable也被設置。 – Edison

+0

你說得對,我沒有正確閱讀文檔。我會更新答案。 – britzl

8

我一直在尋找一種方法來關閉我的觀點,當接觸外面,這些方法都不符合我的需求。我確實找到了一個解決方案,只是在這裏發佈,以防任何人感興趣。

我有一個基本的活動,幾乎所有的活動延伸。在這裏面我有:

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

所以,如果我的看法是可見它只是接近,如果沒有它會像一個正常的觸摸事件。不知道這是否是最好的方式,但它似乎對我有用。

+5

當您的視圖可見並且您點擊它時會發生什麼?看起來它將無論如何關閉它 – Guillaume

+0

非常有幫助。請參閱以下內容以確定觸摸是否位於視圖內,當點擊位於視圖之外時該視圖將消失:http://stackoverflow.com/questions/20700286/how-to-detect-a-motionevent-inside- dispatchtouchevent [鏈接] – dazed

+0

我與@Guillaume,這不是基本無用,因爲你永遠不會點擊你的看法? – behelit

2

我需要特定的能力,不僅在點擊外部時刪除視圖,還允許點擊通過正常的活動。例如,我有一個單獨的佈局notification_bar.xml,我需要動態膨脹並在需要時添加到當前活動的任何位置。

如果我創建覆蓋視圖來獲取notification_bar視圖之外的任何點擊並刪除這些視圖,則父視圖(活動的主視圖)仍未收到任何點擊,這意味着,當notification_bar可見時,需要兩次點擊才能點擊按鈕(一個用於關閉notification_bar視圖,另一個用於單擊該按鈕)。

爲了解決這個問題,你可以創建自己的DismissViewGroup延伸的ViewGroup並重寫了以下方法:

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

然後您的動態添加視圖將看起來有點像:

<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" ... 

這將允許您與視圖進行交互,當您在視圖外單擊時,您都會忽略該視圖並與該活動正常交互。

16

找到視圖矩形,然後檢測點擊事件是否在視圖之外。

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

如果要使用觸摸事件的其他地方,儘量

return super.dispatchTouchEvent(ev); 
+2

只要注意,'dispatchTouchEvent()'應該返回一個布爾值,但是在你的例子中你不會返回任何東西。另外,你不定義也不解釋'viewRect'是什麼。 – CaptJak

+0

謝謝CaptJak。 –

+0

這工作得很好,實施起來很簡單。 – behelit

0

我創建定製的ViewGroup顯示掛靠到其他視圖(彈出氣球)信息框。 子視圖是實際的信息框,BalloonView是全屏幕的絕對定位的孩子,並攔截觸摸。裏面的孩子

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

處理點擊:

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

要消除外部,而沒有委託觸摸到底層查看我的查看方式請點擊:

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

要消除外部,委託觸摸我的視圖通過點擊到底層瀏覽:

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

要解僱後退按鈕按下:

//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

感謝@ituki的想法

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> 

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

它工作時的LinearLayout以外觸摸