如何在我触摸屏幕的位置正上方显示弹出窗口

时间:2017-05-24 01:39:03

标签: android android-layout android-popupwindow

我想在我的代码中显示一个弹出窗口,这样无论我在屏幕上的哪个位置触摸,弹出窗口都会显示在我触摸的位置的正上方。不确定,如何实现这一目标。这是我当前的弹出窗口代码:

 LayoutInflater inflater = (LayoutInflater) getApplicationContext().getSystemService(LAYOUT_INFLATER_SERVICE);

                            View customView = inflater.inflate(R.layout.popup,null);

                            final PopupWindow popupWindow = new PopupWindow(
                                    customView,
                                    LayoutParams.WRAP_CONTENT,
                                    LayoutParams.WRAP_CONTENT);

                            // Set an elevation value for popup window
                            // Call requires API level 21
                            if(Build.VERSION.SDK_INT>=21){
                                popupWindow.setElevation(5.0f);
                            }
                            final TextView placename = (TextView) customView.findViewById(R.id.popup_id) ;
                            Button closeButton = (Button) customView.findViewById(R.id.directions);
                            placename.setText(place.getName());
                            popupWindow.setBackgroundDrawable(new BitmapDrawable());
                            popupWindow.setOutsideTouchable(true);
                            // Set a click listener for the popup window close button
                            closeButton.setOnClickListener(new View.OnClickListener() {
                                @Override
                                public void onClick(View view) {
                                    // Dismiss the popup window

                                    popupWindow.dismiss();

                                }
                            });
                            popupWindow.setFocusable(true);

                            popupWindow.showAtLocation(mapInsideContainer, Gravity.CENTER, 0, 0);
                            popupWindow.showAsDropDown(customView);

这是我的popup.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical"
    android:background="@android:color/background_light">
    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:layout_margin="1dp"
        android:background="@android:color/white">
        >
        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            android:layout_margin="20dp">
            <TextView
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                android:textColor="#000000"
                android:id="@+id/popup_id" />
            <Button
                android:id="@+id/directions"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                android:background="@color/black_overlay"
                android:textColor="@android:color/white"
                android:text="Directions" />
        </LinearLayout>
    </LinearLayout>
</LinearLayout>

目前,由于Gravity.CENTER,它显示在屏幕中央,但我想将它显示在我在屏幕上动态触摸的位置上方。有任何想法吗?感谢

奖励积分如果您可以引导我创建一个聊天气泡,如弹出窗口顶部带有标题,底部带有“位置”按钮,点击屏幕上的位置点击气泡指针

2 个答案:

答案 0 :(得分:1)

这就是我所做的,希望帮助你

customView.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));

popupWindow.showAtLocation(getWindow().getDecorView(), Gravity.NO_GRAVITY, (int)event.getX(), (int)event.getY() - customView.getMeasuredHeight());

并覆盖public boolean onTouchEvent(MotionEvent event)

@Override
    public boolean onTouchEvent(MotionEvent event) {
        popup(event);
        return super.onTouchEvent(event);
    }

编辑: 我的写作跟随,它为我工作。

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        popup(event);
        return super.onTouchEvent(event);
    }

    private void popup(MotionEvent event) {
        LayoutInflater inflater = (LayoutInflater) getApplicationContext().getSystemService(LAYOUT_INFLATER_SERVICE);

        View customView = inflater.inflate(R.layout.popup,null);

        final PopupWindow popupWindow = new PopupWindow(
                customView,
                WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.WRAP_CONTENT);

        // Set an elevation value for popup window
        // Call requires API level 21
        if(Build.VERSION.SDK_INT>=21){
            popupWindow.setElevation(5.0f);
        }
        final TextView placename = (TextView) customView.findViewById(R.id.popup_id) ;
        Button closeButton = (Button) customView.findViewById(R.id.directions);
        placename.setText("Name");
        popupWindow.setBackgroundDrawable(new BitmapDrawable());
        popupWindow.setOutsideTouchable(true);
        // Set a click listener for the popup window close button
        closeButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                // Dismiss the popup window

                popupWindow.dismiss();

            }
        });
//        popupWindow.setFocusable(true);
        popupWindow.setOutsideTouchable(true);
        customView.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
        popupWindow.showAtLocation(getWindow().getDecorView(), Gravity.NO_GRAVITY, (int)event.getX(), (int)event.getY() - customView.getMeasuredHeight());

        getWindow().getDecorView().setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                return false;
            }
        });
    }

}

activity_main.xml中

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/parent"
    android:background="@color/colorAccent"
    android:fitsSystemWindows="true">


</android.support.constraint.ConstraintLayout>

答案 1 :(得分:0)

尝试创建透明的活动,而不是使用PopupWindow,类似于this

然后,您可以为聊天气泡创建自定义绘图(因为气泡指针需要位于不同的位置,具体取决于用户点击的位置)。覆盖onTouchEvent()并获取用户触摸的坐标,然后启动透明活动并将其传递给意图中的坐标,以便您可以将气泡视图放置在适当的位置。

这会增加额外的开销,因为您正在启动一个新的Activity,但它可以让您充分发挥自己想要的自定义外观和行为的能力。

这是一些细节。当我想要自定义弹出菜单时,这就是我所做的。

对于透明活动,创建一个新活动并在清单中为其指定一个主题:

<activity
        android:name=".PopupActivity"
        android:theme="@style/Transparent" />

在styles.xml中:

<style name="Transparent" parent="Theme.AppCompat.NoActionBar">
    <item name="android:windowIsTranslucent">true</item>
    <item name="android:windowBackground">@color/translucent</item>
</style>

您可以将@color/translucent定义为完全透明,我会在其中添加一些灰色,以便在弹出窗口显示时,下面的视图显示为暗淡。

在活动的布局中:

<RelativeLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_popup"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/colorPrimary"
    android:layout_margin="60dp">

这里我使用的是RelativeLayout,但你可以使用你想要的任何布局,重要的是边距。现在活动看起来像这样,背景活动在这一背后可见:

接下来,您将使用触摸坐标动态更改边距,使矩形显示在您想要的任何位置。

我们需要知道屏幕顶部的屏幕大小和密度以及状态栏的高度,因此在主要活动的onCreate()方法中,添加:

//Determine the screen dimensions and density
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
screenWidth = metrics.widthPixels;
screenHeight = metrics.heightPixels;
screenDensity = metrics.density;
int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
int statusBarHeight = (int) (24 * density);
if (resourceId > 0) {
    statusBarHeight = getResources().getDimensionPixelSize(resourceId);
}

这些值不会改变,因此将它们存储在静态变量中,以便其他类可以在需要时获取它们。

现在,在透明活动的onCreate()方法中,根据触摸事件坐标计算边距:

int popupSize = 100;
int rMargin, lMargin, tMargin, bMargin;

lMargin = xCoord - popupSize;
rMargin = screenWidth - xCoord - popupSize;
tMargin = yCoord - popupSize;
bMargin = screenHeight - yCoord - popupSize - statusBarHeight;

RelativeLayout layout = (RelativeLayout) findViewById(R.id.activity_popup);
FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) layout.getLayoutParams();
params.setMargins(lMargin, tMargin, rMargin, bMargin);
layout.setLayoutParams(params);

这会创建一个以触摸坐标为中心的正方形。例如,给定x = 700和y = 1500,我得到:

enter image description here

对于x = 150和y = 200,我得到:

enter image description here

你可以看到,在这种情况下,如果坐标太靠近边缘,你将获得一个负边距,并将裁剪正方形。需要更多的数学来纠正这一点。

我要做的是将屏幕区域划分为四个象限并计算触摸事件所在的象限。然后,例如,如果触摸位于左上象限,则将方块的左上角与触摸对齐坐标。这样,屏幕边缘永远不会裁剪正方形。

就创建带指针的气泡而言,制作4个气泡的自定义绘图,每个绘制指针位于不同的角落。然后,根据触摸事件的象限,加载适当的drawable,使指针始终在正确的方向。

这篇文章虽然有点太长了。