如何制作横向ContextMenu?

时间:2018-02-06 19:13:42

标签: android contextmenu

我制作了一个名为Activity的{​​{1}},我想添加一个水平Accounts。这可能看起来像剪切,复制和粘贴选项。有没有办法在列表项上添加这个水平自定义菜单ContextMenu

这是我到目前为止所得到的。

onLongClick

目前的UI看起来像这样。

Present working condition

这是我想要的东西, enter image description here

5 个答案:

答案 0 :(得分:4)

我认为你需要的是PopupWindow。它更容易实现,并具有自定义布局设置选项。 PopupWindow可以根据需要设置在自定义位置,并且实现您正在考虑的示例复制/粘贴UI的想法也可以通过PopupWindow的实现来提供。

如果您希望使用PopupWindow实现您的情况而不是使用上下文菜单实现它,我发现this answer非常有用。

在上面提到的并且提供了相似的答案中,PopupWindow只有TextView。您可以实现任何自定义/复杂UI,而不是像其中显示的那样简单TextView

我希望有所帮助。

更新

正如评论中所述,获取PopupWindow位置的位置也可以动态设置。我指的是另一个链接,因此您也可以从那里检查实现。

Here's the implementation在列表中使用PopupWindow

答案 1 :(得分:4)

只需通过 QuickAction 库即可实现。

https://github.com/piruin/quickaction
https://github.com/lorensiuswlt/NewQuickAction

enter image description here

希望这会对你有所帮助!!

答案 2 :(得分:0)

我使用Dialog来实现这一目标,仍在寻找标准方法。请发布更好的方法。

Test.java

public void showOptionMenu(View view) {

    int x1 = (int) view.getX();
    int  y1 = (int) view.getY();
    LayoutInflater inflater = LayoutInflater.from(MainActivity.this);
    View v = inflater.inflate(R.layout.popup_window , null);
    Dialog dialog = new Dialog(MainActivity.this);
    dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
    WindowManager.LayoutParams wmlp = dialog.getWindow().getAttributes();
    wmlp.gravity = Gravity.TOP | Gravity.LEFT;
    wmlp.x = x1;   //x position
    wmlp.y = y1;   //y position
    dialog.setContentView(v);
    dialog.show();
}

<强> activity_main.xml中

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.shiva.testacitivity.MainActivity">

<Button
    android:text="Show Options"
    android:onClick="showOptionMenu"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_margin="10dp"/>

</LinearLayout>

<强> popup_windows.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:background="#ECEFF1"
android:padding="5dp"
android:gravity="center"
android:orientation="horizontal">

<TextView
    android:id="@+id/edit"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:drawableLeft="@drawable/edit"
    android:layout_gravity="center"
    android:gravity="center"
    android:textColor="#000"
    android:text="Edit" />

<View
    android:layout_width="1dp"
    android:layout_height="match_parent"/>

<TextView
    android:id="@+id/delete"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:gravity="center"
    android:drawableLeft="@drawable/delete"
    android:text="Delete"
    android:textColor="#000" />


    </LinearLayout>

结果

current UI

答案 3 :(得分:0)

所以,几年前我写了下面的代码。您需要首先创建两个类PopUp,其次是TringleView

  

弹出窗口: - 创建对话框并打开到您的视图附近(您想要的位置)   打开对话框)。 您可以更改弹出式bg颜色

     

TringleView: - 制作tringle视图,或者你可以说尖箭头。你可以改变尖头箭头bg颜色

View contentView = ((FragmentActivity)v.getContext()).getLayoutInflater().inflate(R.layout.edit_delete_layout,getAttachedRecyclerView(),false);

// this view denote where you click or you want to open dialog near 
PopUp.showPopupOnView(((FragmentActivity) v.getContext()).getSupportFragmentManager(),contentView,view,false);

<强> PopUp.class

public class PopUp  extends DialogFragment {

    protected int targetX;
    protected int targetY;
    protected int targetWidth;
    protected int targetHeight;
    protected Bitmap targetViewImage;
    protected View contentView;
    private SmartWorksPopUpViewHolder fragmentViewHolder;
    private static int bgDrawable = R.drawable.round_corner_white_bg;
    protected static int ONE_DIP;
    private static int arrowBgColor = R.color.border_color;
    private static int arrowWidthMultiple = 25;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (ONE_DIP == 0) {
            ONE_DIP = (int) TypedValue.applyDimension(
                    TypedValue.COMPLEX_UNIT_DIP, 1, getResources()
                                                            .getDisplayMetrics());
        }
        setStyle(DialogFragment.STYLE_NO_TITLE, android.R.style.Theme_Translucent);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        AbsoluteLayout parent = new AbsoluteLayout(getActivity());
        parent.setId(R.id.parentLayout);
        return parent;
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        this.fragmentViewHolder = createViewHolder(view);
        bindView(fragmentViewHolder);
    }

    protected SmartWorksPopUpViewHolder createViewHolder(
                                                                View fragmentView) {
        return new SmartWorksPopUpViewHolder(fragmentView, contentView);
    }

    private void bindView(SmartWorksPopUpViewHolder vh) {
        if (fragmentViewHolder != null) {
            setupTargetDummyView(vh);
            boolean showOnTop = shouldShowOnTop();
            setupArrow(vh, showOnTop);
            setupContent(vh, showOnTop);
        }
    }

    protected void setupContent(SmartWorksPopUpViewHolder vh, boolean showOnTop) {
        final int y;
        AbsoluteLayout.LayoutParams arrowParams = (android.widget.AbsoluteLayout.LayoutParams) vh.arrow
                                                                                                       .getLayoutParams();
        int measureHeight = View.MeasureSpec.makeMeasureSpec(
                ViewGroup.LayoutParams.WRAP_CONTENT, View.MeasureSpec.UNSPECIFIED);
        int measureWidth = View.MeasureSpec.makeMeasureSpec(
                getActivity().getWindow().getDecorView().getWidth(), View.MeasureSpec.EXACTLY);
        vh.popupView.measure(measureWidth, measureHeight);
        if (showOnTop) {
            y = this.targetY - vh.popupView.getMeasuredHeight() + ONE_DIP;
        } else {
            y = arrowParams.y + arrowParams.height - ONE_DIP * 2;
        }

        updateAbsoluteLayoutParams(
                getActivity().getResources().getDimensionPixelOffset(R.dimen.sixty_dp),
                y,
                getActivity().getWindow().getDecorView().getWidth() -
                        getActivity().getResources().getDimensionPixelOffset(R.dimen.seventy_dp),
                ViewGroup.LayoutParams.WRAP_CONTENT, vh.popupView);

        vh.parent.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                exit();
            }
        });

    }

    private void setupArrow(SmartWorksPopUpViewHolder vh, boolean showOnTop) {
        final int arrowHeight = 15 * ONE_DIP;
        final int arrowWidth = arrowWidthMultiple * ONE_DIP;
        vh.arrow.setDirectionAndColor(showOnTop ? "down" : "top", vh.popupView.getContext().getResources().getColor(arrowBgColor));
        final int x = (int) (targetX + targetWidth / 3 - arrowWidth / 2);
        final int y = targetY + (showOnTop ? -arrowHeight : targetHeight);
        updateAbsoluteLayoutParams(x, y, arrowWidth, arrowHeight, vh.arrow);
    }

    private void setupTargetDummyView(SmartWorksPopUpViewHolder vh) {
        vh.targetViewDummy.setImageBitmap(targetViewImage);
        updateAbsoluteLayoutParams(targetX, targetY, targetWidth, targetHeight, vh.targetViewDummy);
    }

    protected void updateAbsoluteLayoutParams(int x, int y, int width, int height, View view) {
        AbsoluteLayout.LayoutParams layoutParams =
                (android.widget.AbsoluteLayout.LayoutParams) view.getLayoutParams();
        layoutParams.x = x;
        layoutParams.y = y;
        layoutParams.height = height;
        layoutParams.width = width;
        view.setLayoutParams(layoutParams);
    }

    private boolean shouldShowOnTop() {
        int windowHeight = getActivity().getWindow().getDecorView().getHeight();
        int windowMid = windowHeight / 4;
        return targetY > windowMid;
    }

    @Override
    public void onDestroyView() {
        this.fragmentViewHolder = null;
        super.onDestroyView();
    }

    protected static class SmartWorksPopUpViewHolder {
        protected AbsoluteLayout parent;
        protected View popupView;
        protected TringleView arrow;
        protected AppCompatImageView targetViewDummy;
        protected SmartWorksPopUpViewHolder(View fragmentView, View content) {
            this.parent = (AbsoluteLayout) fragmentView;
            final Context mContext = fragmentView.getContext();
            this.popupView = content;
            this.arrow = new TringleView(mContext);
            this.targetViewDummy = new SmartWorksAppCompactImageView(mContext);

            this.parent.addView(popupView);
            this.parent.addView(arrow);
            this.parent.addView(targetViewDummy);
            this.parent.setBackgroundColor(0x00000000);
            content.setBackgroundResource(bgDrawable);
        }
    }

    public static PopUp showPopupOnView(FragmentManager fm, View contentView, View targetView, boolean showTargetView) {
        int[] location = new int[2];
        targetView.getLocationInWindow(location);
        PopUp fragment = new PopUp();
        fragment.targetX = location[0];
        fragment.targetY = (int) (location[1] - TypedValue
                                                        .applyDimension(TypedValue.COMPLEX_UNIT_DIP, 25,
                                                                targetView.getResources().getDisplayMetrics()));
        fragment.targetWidth = targetView.getMeasuredWidth();
        fragment.targetHeight = targetView.getMeasuredHeight();
        fragment.contentView = contentView;
        fragment.show(fm, "offer");
        return fragment;
    }

    public void exit() {
        dismiss();
    }

    public static void setArrowBackgroundColor(int color) {
        arrowBgColor = color;
    }

    public static void setArrowWidthMultiple(int arrowWidth) {
        arrowWidthMultiple = arrowWidth;
    }
}

<强> TringleView.class

public class TringleView extends View {

    private String direction;
    private int color;

    public TringleView(Context context) {
        super(context);
        setDirectionAndColor("right", Color.RED);
    }

    public TringleView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        setDirectionAndColor(attrs.getAttributeValue(null, "direction"), Color.RED);
    }

    public TringleView(Context context, AttributeSet attrs) {
        super(context, attrs);
        setDirectionAndColor(attrs.getAttributeValue(null, "direction"), Color.RED);
    }

    public void setDirectionAndColor(String direction, int color) {
        if (direction != null && !direction.equals(this.direction) || this.color != color) {
            createTriangleDrawable(direction, color);
        }
    }

    private void createTriangleDrawable(String string, int color) {
        int width = MeasureSpec.makeMeasureSpec(30,  MeasureSpec.UNSPECIFIED);
        int height = MeasureSpec.makeMeasureSpec(20, MeasureSpec.UNSPECIFIED);
        Path path = new Path();
        if (string == null) {
            string = "right";
        }
        if (string.equals("top")) {
            path.moveTo(0, height);
            path.lineTo(width / 2, 0);
            path.lineTo(width, height);
        } else if (string.equals("left")) {
            path.moveTo(width, 0);
            path.lineTo(0, height / 2);
            path.lineTo(width, height);
        } else if (string.equals("right")) {
            path.moveTo(0, 0);
            path.lineTo(width, height / 2);
            path.lineTo(0, height);
        } else if (string.equals("down")) {
            path.moveTo(0, 0);
            path.lineTo(width / 2, height);
            path.lineTo(width, 0);
        }

        path.close();
        ShapeDrawable shapeDrawable = new ShapeDrawable(new PathShape(path, width, height));
        shapeDrawable.getPaint().setColor(color);
        setBackground(shapeDrawable);
        this.color = color;
        this.direction = string;
    }

}

<强> edit_delete_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
    app:cardCornerRadius="@dimen/five_dp"
    android:layout_margin="@dimen/ten_dp"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    app:layout_behavior="android.support.design.widget.BottomSheetBehavior"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" >
    <LinearLayout
        app:layout_behavior="android.support.design.widget.BottomSheetBehavior"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:weightSum="5"
        android:gravity="center"
        android:orientation="horizontal"
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto">
        <sis.com.smartworks.widget.SmartWorksTextView
            android:id="@+id/share"
            android:textSize="@dimen/smallest_text_size"
            android:textColor="@color/black"
            android:visibility="visible"
            android:gravity="center"
            android:paddingRight="@dimen/four_dp"
            android:paddingLeft="@dimen/four_dp"
            android:paddingTop="@dimen/ten_dp"
            android:paddingBottom="@dimen/ten_dp"
            android:text="Share"
            android:layout_weight="1"
            android:textStyle="bold"
            android:layout_width="0dp"
            android:layout_height="wrap_content" />
        <View
            android:layout_width="1dp"
            android:background="@color/grey_unselect"
            android:layout_height="match_parent" />
        <sis.com.smartworks.widget.SmartWorksTextView
            android:id="@+id/reportSpam"
            android:textSize="@dimen/smallest_text_size"
            android:textColor="@color/black"
            android:visibility="visible"
            android:gravity="center"
            android:paddingRight="@dimen/four_dp"
            android:paddingLeft="@dimen/four_dp"
            android:paddingTop="@dimen/ten_dp"
            android:paddingBottom="@dimen/ten_dp"
            android:text="Spam"
            android:layout_weight="1"
            android:textStyle="bold"
            android:layout_width="0dp"
            android:layout_height="wrap_content" />
        <View
            android:layout_width="1dp"
            android:background="@color/grey_unselect"
            android:layout_height="match_parent" />
        <!--<View-->
            <!--android:layout_width="match_parent"-->
            <!--android:layout_marginLeft="@dimen/three_dp"-->
            <!--android:layout_marginRight="@dimen/three_dp"-->
            <!--android:background="@color/white"-->
            <!--android:layout_height="@dimen/one_dp" />-->


        <sis.com.smartworks.widget.SmartWorksTextView
            android:id="@+id/edit"
            android:textSize="@dimen/smallest_text_size"
            android:textColor="@color/black"
            android:gravity="center"
            android:paddingRight="@dimen/four_dp"
            android:paddingLeft="@dimen/four_dp"
            android:paddingTop="@dimen/ten_dp"
            android:paddingBottom="@dimen/ten_dp"
            app:swFontName="robotoNormal"
            android:layout_weight="1"
            android:text="@string/edit"
            android:textStyle="bold"
            android:layout_width="0dp"
            android:layout_height="wrap_content" />
        <View
            android:layout_width="1dp"
            android:background="@color/grey_unselect"
            android:layout_height="match_parent" />
        <!--<View-->
            <!--android:layout_width="match_parent"-->
            <!--android:layout_marginLeft="@dimen/three_dp"-->
            <!--android:layout_marginRight="@dimen/three_dp"-->
            <!--android:background="@color/white"-->
            <!--android:layout_height="@dimen/one_dp" />-->

        <sis.com.smartworks.widget.SmartWorksTextView
            android:id="@+id/delete"
            android:textSize="@dimen/smallest_text_size"
            android:textColor="@color/black"
            android:gravity="center"

            android:paddingRight="@dimen/four_dp"
            android:paddingLeft="@dimen/four_dp"
            android:paddingTop="@dimen/ten_dp"
            android:paddingBottom="@dimen/ten_dp"            android:layout_weight="1"
            android:text="@string/delete"
            android:textStyle="bold"
            android:layout_width="0dp"
            android:layout_height="wrap_content" />
        <View
            android:layout_width="1dp"
            android:background="@color/grey_unselect"
            android:layout_height="match_parent" />
        <sis.com.smartworks.widget.SmartWorksTextView
            android:id="@+id/cancel"
            android:textSize="@dimen/smallest_text_size"
            android:textColor="@color/black"
            android:gravity="center"
            android:layout_weight="1"
            android:visibility="visible"
            android:paddingRight="@dimen/four_dp"
            android:paddingLeft="@dimen/four_dp"
            android:paddingTop="@dimen/ten_dp"
            android:paddingBottom="@dimen/ten_dp"
            android:textStyle="bold"
            android:text="@string/select_cancel"
            android:layout_width="0dp"
            android:layout_height="wrap_content" />
    </LinearLayout>

</android.support.v7.widget.CardView>

<强>结果

![enter image description here

因此,如果您想将视图设置为水平视图,则需要根据您的要求进行水平布局。因此,可以执行此任务来更改您放入edit_delete_layout.xml然后传递到contentView的{​​{1}}。

注意: - 您可以根据自己的要求自定义弹出类,我知道此代码有很多不推荐的视图,因此您可以自行更新。

答案 4 :(得分:0)

要显示紧凑的上下文菜单,您需要为ActionMode创建Menu,让我告诉您如何:

  
    

假设您的操作菜单XML具有删除,复制和转发操作:

  
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <item
        android:id="@+id/action_copy"
        android:icon="@drawable/ic_vector_menu_copy"
        android:title="Copy"
        app:showAsAction="always" />
    <item
        android:id="@+id/action_delete"
        android:icon="@drawable/ic_vector_menu_delete"
        android:title="Delete"
        app:showAsAction="always" />
    <item
        android:id="@+id/action_forward"
        android:icon="@drawable/ic_vector_menu_forward"
        android:title="Forward"
        app:showAsAction="always" />
</menu>
  
    

在您的活动中创建操作菜单

  
//Global variable in Activity/Fragment to manage close the menu
private ActionMode mActionMode;

//Action mode callbacks
//Contextual Action bar -  for showing delete/copy/... on action bar
private ActionMode.Callback mActionModeCallback = new ActionMode.Callback() {

    // Called when the action mode is created; startActionMode() was called
    @Override
    public boolean onCreateActionMode(ActionMode mode, Menu menu) {
        // Inflate a menu resource providing context menu items
        MenuInflater inflater = mode.getMenuInflater();
        inflater.inflate(R.menu.menu_contextual_action, menu);
        return true;
    }

    // Called each time the action mode is shown.
    // Always called after onCreateActionMode, but
    // may be called multiple times if the mode is invalidated.
    @Override
    public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
        return false; // Return false if nothing is done
    }

    // Called when the user selects a contextual menu item
    @Override
    public boolean onActionItemClicked(final ActionMode mode, MenuItem item) {
        switch (item.getItemId()) {
            case R.id.action_delete:
                //Do the delete action 
                //mAdapter.resetSelection();
                mode.finish(); // Action picked, so close the TAB
                //showToast "Deleted successfully"
                return true;
            case R.id.action_copy:
                //mAdapter.resetSelection();
                MyClipboardManager.copyToClipboard(ChatDetailActivity.this, mAdapter.getSelectedMessageText());
                mode.finish(); // Action picked, so close the TAB
                //showToast "Text copied to clipboard"
                return true;
            default:
                return false;
        }
    }

    // Called when the user exits the action mode
    @Override
    public void onDestroyActionMode(ActionMode mode) {
        mActionMode = null;
        //mAdapter.resetSelection();
    }
};

@Override
public void onBackPressed() {
    //Closing menu first if it's visible rather than doing the back press action  
    if (mActionMode != null && mActionMode.getMenu().hasVisibleItems()) {
        mActionMode.finish();
        return;
    }
    super.onBackPressed();
}

@Override
public void onDestroy() {
    //Closing menu
    if (mActionMode != null) {
        mActionMode.finish();
    }
    super.onDestroy();
}

*将回调设置为全局操作模式变量

mActionMode = startSupportActionMode(mActionModeCallback);

*将标题设置为菜单

mActionMode.setTitle("Menu title");

*设置值

后使菜单无效
mActionMode.invalidate();
  
    

管理紧凑上下文菜单的样式

  
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <!-- Customize your theme here. -->
    <item name="colorPrimary">@color/colorPrimary</item>
    <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
    <item name="colorAccent">@color/colorAccent</item>
    <item name="android:windowDisablePreview">true</item>

    <!--CONTEXTUAL action MODE-->
    <item name="android:windowContentOverlay">@null</item>
    <!--ActionMode background color-->
    <!-- <item name="android:actionModeBackground">@color/colorPrimary</item>-->
    <!--To Overlay existing toolbar, NOTE We are not using android: to let it work everywhere-->
    <item name="windowActionModeOverlay">true</item>
    <item name="actionModeStyle">@style/AppActionModeStyle</item>
    <item name="android:actionModeCloseDrawable">@drawable/ic_arrow_back_24dp</item>
</style>

<style name="AppActionModeStyle" parent="@style/Widget.AppCompat.ActionMode">
    <!--ActionMode background color-->
    <item name="background">@color/colorPrimary</item>
   <!--ActionMode text title color-->
    <item name="titleTextStyle">@style/ActionModeTitleTextStyle</item>
</style>

<style name="ActionModeTitleTextStyle" parent="@style/TextAppearance.AppCompat.Widget.ActionMode.Title">
    <item name="android:textColor">@android:color/white</item>
</style>