【问题标题】:How do I display a popupwindow right above the place i touched on screen如何在我在屏幕上触摸的位置上方显示一个弹出窗口
【发布时间】:2017-05-24 01:39:03
【问题描述】:

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

 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,目前它显示在屏幕的中心,但我想将它显示在我在屏幕上动态触摸的位置的正上方。有任何想法吗?谢谢

如果你能指导我创建一个聊天气泡,比如顶部的标题和底部的“地点”按钮,气泡指针位于屏幕上点击的位置,那么奖励积分

【问题讨论】:

    标签: android android-layout android-popupwindow


    【解决方案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>
    

    【讨论】:

    • (int)event.getY() 和 (int)event.getX() ,这里有什么事件?它显示为错误
    • 我不知道你真正需要的目标视图,触摸它以显示弹出窗口,所以我覆盖了活动public boolean onTouchEvent(MotionEvent event),所以参数事件是(int)event.getX()中的那个事件,如果你的目标视图是mapInsideContainer ,你可以使用public void setOnTouchListener(OnTouchListener l)
    • 也不起作用。有没有更简单的计算方法
    【解决方案2】:

    不要使用PopupWindow,而是尝试创建一个透明的Activity,类似于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,我得到:

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

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

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

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

    不过,这篇文章有点太长了。

    【讨论】:

    • 如果你能提供有用的细节,因为透明活动部分令人困惑,我不知道如何解决弹出窗口不显示在触摸点正上方的问题
    • @JusticeBauer 我编辑了我的答案以提供一些细节。今晚我会编辑更多,但我现在得走了。
    • @JusticeBauer 我添加了更多细节。
    • 谢谢你,杰森。很快就会测试出来,让你知道它是怎么回事!
    • 这里的 xcord 是什么?
    猜你喜欢
    • 2021-11-16
    • 1970-01-01
    • 1970-01-01
    • 2020-12-09
    • 2011-03-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-03
    相关资源
    最近更新 更多