FrameLayout 上的 onTouchListener:在外部单击时关闭它
onTouchListener on FrameLayout: close it when clicked outside
我发现很难实现一个可能很简单的功能。
我有一个包含下拉菜单的 FrameLayout(就像 WhatsApp 中的那个,当您单击附件图标时弹出)。
当我在所说的 FrameLayout 之外单击时,我想关闭它。
我正在尝试使用 onTouch 事件来实现它,但没有成功。
我的代码:
public class MainActivity extends AppCompatActivity {
private LinearLayout mRevealView;
private FrameLayout mRevealFrame;
...
@Override
protected void onCreate(Bundle savedInstanceState) {
...
mRevealView = (LinearLayout) findViewById(R.id.rows);
mRevealFrame = (FrameLayout) findViewById(R.id.reveal_frame);
...
}
// This method is called when I click on the right menu icon.
public void fuelTypes() {
// Looking for X and Y coordinates.
int cx = (mRevealView.getLeft() + mRevealView.getRight());
int cy = (mRevealView.getTop());
// Looking for radius when icon is tapped for showing layout.
int startRadius = 0;
int endRadius = Math.max(mRevealView.getWidth(), mRevealView.getHeight());
// Performing circular reveal when icon will be tapped.
Animator animator = ViewAnimationUtils.createCircularReveal(mRevealView, cx, cy, startRadius, endRadius);
animator.setInterpolator(new AccelerateDecelerateInterpolator());
animator.setDuration(400);
// Reverse animation to find radius when icon is tapped again for hiding layout.
// The starting radius will be the radius or the extent to which circular reveal animation is to be shown.
int reverseStartRadius = Math.max(mRevealView.getWidth(), mRevealView.getHeight());
// End - radius will be zero.
int reverseEndRadius = 0;
// Performing circular reveal for reverse animation.
Animator animate = ViewAnimationUtils.createCircularReveal(mRevealView, cx, cy, reverseStartRadius, reverseEndRadius);
if (hidden) {
// To show the layout when the icon is tapped.
mRevealView.setVisibility(View.VISIBLE);
mRevealFrame.setVisibility(View.VISIBLE);
animator.start();
hidden = false;
} else {
mRevealView.setVisibility(View.VISIBLE);
mRevealFrame.setVisibility(View.VISIBLE);
// To hide layout on animation end.
animate.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
mRevealView.setVisibility(View.INVISIBLE);
mRevealFrame.setVisibility(View.INVISIBLE);
hidden = true;
}
});
animate.start();
}
mRevealFrame.setOnTouchListener(new FrameLayout.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
Log.d("MOTION_EVENT", "getAction(): " + motionEvent.getAction());
switch (motionEvent.getAction()) {
case MotionEvent.ACTION_UP:
Log.d("REVEAL_FRAME", "motion event: " + "ACTION_UP");
fuelTypes();
return true;
}
return true;
}
});
}
第一个Log.d()
起作用了,说明监听器被触发了。
尽管如此,该方法仍未进入 switch
内部:我已经尝试了很多标志,但没有成功。
我读过 onInterceptTouchEvent
和 onTouchEvent
,但我不知道如何使用它们来代替 OnTouchListener
。
感谢您的帮助。
您的布局:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/main_layout" // give id here
tools:context="com.myfuel.MainActivity">
<include layout="@layout/activity_main"/>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/reveal_frame"
android:layout_marginTop="?attr/actionBarSize">
// EVERYTHING INSIDE THIS WILL BE AS IT IS
</FrameLayout>
</FrameLayout>
你的Activity
public class MainActivity extends AppCompatActivity {
private LinearLayout mRevealView;
private FrameLayout mRevealFrame;
private FrameLayout mMainLayout;
...
@Override
protected void onCreate(Bundle savedInstanceState) {
...
mRevealView = (LinearLayout) findViewById(R.id.rows);
mRevealFrame = (FrameLayout) findViewById(R.id.reveal_frame);
mMainLayout = (FrameLayout) findViewById(R.id.main_layout);
mMainLayout.setOnTouchListener(new FrameLayout.OnTouchListener()
{
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
Log.d("MOTION_EVENT", "getAction(): " + motionEvent.getAction());
//Things changed here
if(!hidden)
fuelTypes();
return false;
}
});
...
}
由于您的 mRevealFrame
没有定义您的 activity 的整个 FrameLayout
,我们不能用它来关闭 mRevealView
。看到我已经定义了 mMainLayout
,它涵盖了现在可以使用的整个布局。
试一试,如果还有问题请告诉我。
使用 PopupWindow
而不是 FrameLayout
。它不应该以这种方式使用。
PopupWindow
将满足您的需求。
https://developer.android.com/reference/android/widget/PopupWindow.html
我发现很难实现一个可能很简单的功能。 我有一个包含下拉菜单的 FrameLayout(就像 WhatsApp 中的那个,当您单击附件图标时弹出)。 当我在所说的 FrameLayout 之外单击时,我想关闭它。
我正在尝试使用 onTouch 事件来实现它,但没有成功。
我的代码:
public class MainActivity extends AppCompatActivity {
private LinearLayout mRevealView;
private FrameLayout mRevealFrame;
...
@Override
protected void onCreate(Bundle savedInstanceState) {
...
mRevealView = (LinearLayout) findViewById(R.id.rows);
mRevealFrame = (FrameLayout) findViewById(R.id.reveal_frame);
...
}
// This method is called when I click on the right menu icon.
public void fuelTypes() {
// Looking for X and Y coordinates.
int cx = (mRevealView.getLeft() + mRevealView.getRight());
int cy = (mRevealView.getTop());
// Looking for radius when icon is tapped for showing layout.
int startRadius = 0;
int endRadius = Math.max(mRevealView.getWidth(), mRevealView.getHeight());
// Performing circular reveal when icon will be tapped.
Animator animator = ViewAnimationUtils.createCircularReveal(mRevealView, cx, cy, startRadius, endRadius);
animator.setInterpolator(new AccelerateDecelerateInterpolator());
animator.setDuration(400);
// Reverse animation to find radius when icon is tapped again for hiding layout.
// The starting radius will be the radius or the extent to which circular reveal animation is to be shown.
int reverseStartRadius = Math.max(mRevealView.getWidth(), mRevealView.getHeight());
// End - radius will be zero.
int reverseEndRadius = 0;
// Performing circular reveal for reverse animation.
Animator animate = ViewAnimationUtils.createCircularReveal(mRevealView, cx, cy, reverseStartRadius, reverseEndRadius);
if (hidden) {
// To show the layout when the icon is tapped.
mRevealView.setVisibility(View.VISIBLE);
mRevealFrame.setVisibility(View.VISIBLE);
animator.start();
hidden = false;
} else {
mRevealView.setVisibility(View.VISIBLE);
mRevealFrame.setVisibility(View.VISIBLE);
// To hide layout on animation end.
animate.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
mRevealView.setVisibility(View.INVISIBLE);
mRevealFrame.setVisibility(View.INVISIBLE);
hidden = true;
}
});
animate.start();
}
mRevealFrame.setOnTouchListener(new FrameLayout.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
Log.d("MOTION_EVENT", "getAction(): " + motionEvent.getAction());
switch (motionEvent.getAction()) {
case MotionEvent.ACTION_UP:
Log.d("REVEAL_FRAME", "motion event: " + "ACTION_UP");
fuelTypes();
return true;
}
return true;
}
});
}
第一个Log.d()
起作用了,说明监听器被触发了。
尽管如此,该方法仍未进入 switch
内部:我已经尝试了很多标志,但没有成功。
我读过 onInterceptTouchEvent
和 onTouchEvent
,但我不知道如何使用它们来代替 OnTouchListener
。
感谢您的帮助。
您的布局:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/main_layout" // give id here
tools:context="com.myfuel.MainActivity">
<include layout="@layout/activity_main"/>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/reveal_frame"
android:layout_marginTop="?attr/actionBarSize">
// EVERYTHING INSIDE THIS WILL BE AS IT IS
</FrameLayout>
</FrameLayout>
你的Activity
public class MainActivity extends AppCompatActivity {
private LinearLayout mRevealView;
private FrameLayout mRevealFrame;
private FrameLayout mMainLayout;
...
@Override
protected void onCreate(Bundle savedInstanceState) {
...
mRevealView = (LinearLayout) findViewById(R.id.rows);
mRevealFrame = (FrameLayout) findViewById(R.id.reveal_frame);
mMainLayout = (FrameLayout) findViewById(R.id.main_layout);
mMainLayout.setOnTouchListener(new FrameLayout.OnTouchListener()
{
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
Log.d("MOTION_EVENT", "getAction(): " + motionEvent.getAction());
//Things changed here
if(!hidden)
fuelTypes();
return false;
}
});
...
}
由于您的 mRevealFrame
没有定义您的 activity 的整个 FrameLayout
,我们不能用它来关闭 mRevealView
。看到我已经定义了 mMainLayout
,它涵盖了现在可以使用的整个布局。
试一试,如果还有问题请告诉我。
使用 PopupWindow
而不是 FrameLayout
。它不应该以这种方式使用。
PopupWindow
将满足您的需求。
https://developer.android.com/reference/android/widget/PopupWindow.html