欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

仿IOS底部弹出框

程序员文章站 2022-04-09 23:12:27
...

仿IOS底部弹出框

最近在公司的项目中涉及到这方面的需求,就想着封装个类。

首先是资源类drawable
仿IOS底部弹出框仿IOS底部弹出框
action_sheet_bottom.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:drawable="@drawable/action_sheet_bottom_pressed" android:state_pressed="true"/>
    <item android:drawable="@drawable/action_sheet_bottom_pressed" android:state_selected="true"/>
    <item android:drawable="@drawable/action_sheet_bottom_normal"/>

</selector>

action_sheet_cancel.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:drawable="@drawable/action_sheet_single_pressed" android:state_pressed="true" />
    <item android:drawable="@drawable/action_sheet_single_normal" />

</selector>

action_sheet_middle.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:drawable="@drawable/action_sheet_middle_pressed" android:state_pressed="true" />
    <item android:drawable="@drawable/action_sheet_middle_pressed" android:state_selected="true" />
    <item android:drawable="@drawable/action_sheet_middle_normal" />

</selector>

action_sheet_single.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:drawable="@drawable/action_sheet_single_pressed" android:state_pressed="true" />
    <item android:drawable="@drawable/action_sheet_single_pressed" android:state_selected="true" />
    <item android:drawable="@drawable/action_sheet_single_normal" />

</selector>

action_sheet_top.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:drawable="@drawable/action_sheet_top_pressed" android:state_pressed="true"/>
    <item android:drawable="@drawable/action_sheet_top_pressed" android:state_selected="true"/>
    <item android:drawable="@drawable/action_sheet_top_normal"/>

</selector>

action_sheet_bottom_normal.xml

<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle" >

    <solid android:color="@color/white" />

    <corners
        android:bottomLeftRadius="15dp"
        android:bottomRightRadius="15dp" />

    <padding
        android:bottom="12dp"
        android:left="24dp"
        android:right="24dp"
        android:top="12dp" />
</shape>

action_sheet_bottom_pressed.xml

<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">

    <solid android:color="@color/ash" />

    <corners
        android:bottomLeftRadius="15dp"
        android:bottomRightRadius="15dp" />

    <padding
        android:bottom="12dp"
        android:left="24dp"
        android:right="24dp"
        android:top="12dp" />

</shape>

action_sheet_middle_normal.xml

<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle" >

    <solid android:color="@color/white" />

    <padding
        android:bottom="12dp"
        android:left="24dp"
        android:right="24dp"
        android:top="12dp" />
</shape>

action_sheet_middle_pressed.xml

<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle" >

    <solid android:color="@color/ash" />


    <padding
        android:bottom="12dp"
        android:left="24dp"
        android:right="24dp"
        android:top="12dp" />

</shape>

action_sheet_single_normal.xml

<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle" >

    <solid android:color="@color/white" />

    <corners android:radius="15dp" />

    <padding
        android:bottom="12dp"
        android:left="24dp"
        android:right="24dp"
        android:top="12dp" />

</shape>

action_sheet_single_pressed.xml

<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle" >

    <solid android:color="@color/ash" />

    <corners android:radius="15dp" />

    <padding
        android:bottom="12dp"
        android:left="24dp"
        android:right="24dp"
        android:top="12dp" />

</shape>

action_sheet_top_normal.xml

<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle" >

    <solid android:color="@color/white" />

    <corners
        android:topLeftRadius="15dp"
        android:topRightRadius="15dp" />

    <padding
        android:bottom="12dp"
        android:left="24dp"
        android:right="24dp"
        android:top="12dp" />

</shape>

action_sheet_top_pressed.xml

<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle" >

    <solid android:color="@color/ash" />

    <corners
        android:topLeftRadius="15dp"
        android:topRightRadius="15dp" />

    <padding
        android:bottom="12dp"
        android:left="24dp"
        android:right="24dp"
        android:top="12dp" />

</shape>

至此,枯燥的资源类已经全部完成,接下来是定义主题样式
仿IOS底部弹出框
相关的两个文件放在values中才能被加载。

actionsheet__attrs.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <declare-styleable name="ActionSheets">
        <attr name="actionSheetStyle" format="reference" />
    </declare-styleable>
    <declare-styleable name="ActionSheet">
        <attr name="actionSheetBackground" format="color|reference" />
        <attr name="cancelButtonBackground" format="color|reference" />
        <attr name="otherButtonTopBackground" format="color|reference" />
        <attr name="otherButtonMiddleBackground" format="color|reference" />
        <attr name="otherButtonBottomBackground" format="color|reference" />
        <attr name="otherButtonSingleBackground" format="color|reference" />
        <attr name="cancelButtonTextColor" format="color|reference" />
        <attr name="otherButtonTextColor" format="color|reference" />
        <attr name="actionSheetPadding" format="dimension|reference" />
        <attr name="otherButtonSpacing" format="dimension|reference" />
        <attr name="cancelButtonMarginTop" format="dimension|reference" />
        <attr name="actionSheetTextSize" format="dimension|reference" />
    </declare-styleable>

</resources>

actionsheet__theme.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <style name="ActionSheetStyle">
        <item name="actionSheetBackground">@android:color/transparent</item>
        <item name="cancelButtonBackground">@drawable/action_sheet_cancel</item>
        <item name="otherButtonTopBackground">@drawable/action_sheet_top</item>
        <item name="otherButtonMiddleBackground">@drawable/action_sheet_middle</item>
        <item name="otherButtonBottomBackground">@drawable/action_sheet_bottom</item>
        <item name="otherButtonSingleBackground">@drawable/action_sheet_single</item>
        <item name="cancelButtonTextColor">@color/black</item>
        <item name="otherButtonTextColor">@color/black</item>
        <item name="actionSheetPadding">10dp</item>
        <item name="otherButtonSpacing">0dp</item>
        <item name="cancelButtonMarginTop">10dp</item>
        <item name="actionSheetTextSize">16sp</item>
    </style>

</resources>

准备工作已经全部完成,接下来就是封装了。

/*
 * 描述:仿ios底部弹出菜单栏
 */
public class ActionSheet extends Dialog implements OnClickListener {

    //控件ID
    private static final int BG_VIEW_ID = 10;
    private static final int CANCEL_BUTTON_ID = 100;
    //动画时常
    private static final int ALPHA_DURATION = 150;
    private static final int TRANSLATE_DURATION = 150;

    private Context mContext;
    private Attributes mAttrs;
    private View mView;
    private List<String> items;
    private List<MenuItemClickListener> itemsListener;

    private View mBg;
    private LinearLayout mPanel;
    private boolean mDismissed = true;//是否可以弹框
    private String cancelTitle = "取消";//底部按钮显示
    private boolean mCancelableOnTouchOutside;

    public ActionSheet(Context context) {
        super(context, android.R.style.Theme_Light_NoTitleBar);
        this.mContext = context;

        InputMethodHidden();
        initViews();
        removeBackground();
    }

    /**
     * 添加条目
     */
    public void addItem(String item, MenuItemClickListener menuItemClickListener) {
        if (null != item) {
            items.add(item);
            itemsListener.add(menuItemClickListener);
        }
    }

    /**
     * 改变底部按钮文字
     */
    public ActionSheet setCancelButtonTitle(String tltle) {
        this.cancelTitle = tltle;
        return this;
    }

    /**
     * 点击外部视图是否消失
     */
    public ActionSheet setCancelableOnTouchMenuOutside(boolean cancelable) {
        this.mCancelableOnTouchOutside = cancelable;
        return this;
    }

    //视图显示
    public void showMenu() {
        if (!mDismissed) return;
        createItems();
        super.show();
        getWindow().setContentView(mView);
        mDismissed = false;
    }

    @Override
    public void onClick(View v) {
        if (v.getId() == BG_VIEW_ID && !mCancelableOnTouchOutside) return;
        dismissMenu();
        if (v.getId() != CANCEL_BUTTON_ID && v.getId() != BG_VIEW_ID) {
            final int position = v.getId() - CANCEL_BUTTON_ID - 1;
            if (0 <= position && null != itemsListener && position < itemsListener.size()) {
                new Handler().postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        itemsListener.get(position).onItemClick(position);
                    }
                }, TRANSLATE_DURATION);
            }
        }
    }

    /**
     * 输入法隐藏
     */
    private void InputMethodHidden() {
        InputMethodManager imm = (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE);
        if (null != imm && imm.isActive()) {
            View currentFocus = getCurrentFocus();
            if (currentFocus != null) imm.hideSoftInputFromWindow(currentFocus.getWindowToken(), 0);
        }
    }

    //初始化
    private void initViews() {
        mContext.setTheme(R.style.ActionSheetStyle);//动态设置 需隐藏本行
        mAttrs = readAttribute();
        mView = createView();
        mBg.startAnimation(createAlphaInAnimation());
        mPanel.startAnimation(createTranslationInAnimation());

        items = new ArrayList<>();
        itemsListener = new ArrayList<>();
    }

    /**
     * 去掉黑色背景
     */
    private void removeBackground() {
        getWindow().setGravity(Gravity.BOTTOM);
        Drawable drawable = new ColorDrawable();
        drawable.setAlpha(0);// 去除黑色背景
        getWindow().setBackgroundDrawable(drawable);
    }

    /**
     * 创建背景视图
     */
    private View createView() {
        FrameLayout parent = new FrameLayout(mContext);
        FrameLayout.LayoutParams parentParams = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                LayoutParams.MATCH_PARENT);
        parentParams.gravity = Gravity.BOTTOM;
        parent.setLayoutParams(parentParams);
        mBg = new View(mContext);
        mBg.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
        mBg.setBackgroundColor(Color.argb(136, 0, 0, 0));
        mBg.setId(BG_VIEW_ID);
        mBg.setOnClickListener(this);

        mPanel = new LinearLayout(mContext);
        FrameLayout.LayoutParams mPanelParams = new FrameLayout.LayoutParams(
                FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT);
        mPanelParams.gravity = Gravity.BOTTOM;
        mPanel.setLayoutParams(mPanelParams);
        mPanel.setOrientation(LinearLayout.VERTICAL);
        parent.addView(mBg);
        parent.addView(mPanel);
        return parent;
    }

    /**
     * 创建条目
     */
    private void createItems() {
        mPanel.removeAllViews();
        ColorStateList color = getContext().getResources().getColorStateList(R.color.black);//条目字体颜色
        if (null != items && items.size() > 0) for (int i = 0; i < items.size(); i++) {
            TextView textView = new TextView(mContext);
            textView.setId(CANCEL_BUTTON_ID + i + 1);
            textView.setOnClickListener(this);
            textView.setBackgroundDrawable(getItemBackground(items.toArray(new String[items.size()]), i));
            textView.setGravity(Gravity.CENTER);
            textView.setText(items.get(i));
            textView.setTextColor(color);
            textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, mAttrs.actionSheetTextSize);
            if (i > 0) {
                View line = new View(mContext);
                line.setBackgroundColor(0xFFD9D9DE);
                line.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, 1));
                mPanel.addView(line);
            }
            mPanel.addView(textView);
        }
        TextView textView = new TextView(mContext);
        textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, mAttrs.actionSheetTextSize);
        textView.setId(CANCEL_BUTTON_ID);
        textView.setBackgroundDrawable(mAttrs.cancelButtonBackground);
        textView.setGravity(Gravity.CENTER);
        textView.setText(cancelTitle);
        textView.setTextColor(color);
        textView.setOnClickListener(this);
        LinearLayout.LayoutParams params = createButtonLayoutParams();
        params.topMargin = mAttrs.cancelButtonMarginTop;
        mPanel.addView(textView, params);

        mPanel.setBackgroundDrawable(mAttrs.background);
        mPanel.setPadding(mAttrs.padding, mAttrs.padding, mAttrs.padding, mAttrs.padding);
    }

    /**
     * 销毁视图
     */
    private void dismissMenu() {
        if (mDismissed) {
            return;
        }
        onDismiss();
        mDismissed = true;
    }

    private void onDismiss() {
        mPanel.startAnimation(createTranslationOutAnimation());
        mBg.startAnimation(createAlphaOutAnimation());
    }

    /**
     * 读取自定义attr属性
     */
    private Attributes readAttribute() {
        Attributes attributes = new Attributes(mContext);
        TypedArray a = mContext.getTheme().obtainStyledAttributes(null, R.styleable.ActionSheet,
                R.attr.actionSheetStyle, 0);
        Drawable background = a.getDrawable(R.styleable.ActionSheet_actionSheetBackground);
        if (null != background) attributes.background = background;
        Drawable cancelButtonBackground = a.getDrawable(R.styleable.ActionSheet_cancelButtonBackground);
        if (null != cancelButtonBackground)
            attributes.cancelButtonBackground = cancelButtonBackground;
        Drawable otherButtonTopBackground = a.getDrawable(R.styleable.ActionSheet_otherButtonTopBackground);
        if (null != otherButtonTopBackground)
            attributes.otherButtonTopBackground = otherButtonTopBackground;
        Drawable otherButtonMiddleBackground = a.getDrawable(R.styleable.ActionSheet_otherButtonMiddleBackground);
        if (null != otherButtonMiddleBackground)
            attributes.otherButtonMiddleBackground = otherButtonMiddleBackground;
        Drawable otherButtonBottomBackground = a.getDrawable(R.styleable.ActionSheet_otherButtonBottomBackground);
        if (null != otherButtonBottomBackground)
            attributes.otherButtonBottomBackground = otherButtonBottomBackground;
        Drawable otherButtonSingleBackground = a.getDrawable(R.styleable.ActionSheet_otherButtonSingleBackground);
        if (null != otherButtonSingleBackground)
            attributes.otherButtonSingleBackground = otherButtonSingleBackground;
        attributes.cancelButtonTextColor = a.getColor(R.styleable.ActionSheet_cancelButtonTextColor, attributes.cancelButtonTextColor);
        attributes.otherButtonTextColor = a.getColor(R.styleable.ActionSheet_otherButtonTextColor, attributes.otherButtonTextColor);
        attributes.padding = (int) a.getDimension(R.styleable.ActionSheet_actionSheetPadding, attributes.padding);
        attributes.otherButtonSpacing = (int) a.getDimension(R.styleable.ActionSheet_otherButtonSpacing, attributes.otherButtonSpacing);
        attributes.cancelButtonMarginTop = (int) a.getDimension(R.styleable.ActionSheet_cancelButtonMarginTop, attributes.cancelButtonMarginTop);
        attributes.actionSheetTextSize = a.getDimensionPixelSize(R.styleable.ActionSheet_actionSheetTextSize, (int) attributes.actionSheetTextSize);
        a.recycle();
        return attributes;
    }

    /**
     * 条目样式
     */
    private Drawable getItemBackground(String[] titles, int item) {
        Log.d("getItemBackground",titles.length+"--"+item);
        if (1 == titles.length) return mAttrs.otherButtonSingleBackground;
        else if (2 == titles.length) switch (item) {
            case 0:
                return mAttrs.otherButtonTopBackground;
            case 1:
                return mAttrs.otherButtonBottomBackground;
            default:
                return null;
        }
        else if (2 < titles.length) if (0 == item) return mAttrs.otherButtonTopBackground;
        else if (item == (titles.length - 1)) return mAttrs.otherButtonBottomBackground;
        else return mAttrs.getOtherButtonMiddleBackground;
        return null;
    }

    /**
     * 加载视图-透明度动画
     */
    private Animation createAlphaInAnimation() {
        AlphaAnimation an = new AlphaAnimation(0, 1);
        an.setDuration(ALPHA_DURATION);
        return an;
    }

    /**
     * 加载视图-位移动画
     */
    private Animation createTranslationInAnimation() {
        int type = TranslateAnimation.RELATIVE_TO_SELF;
        TranslateAnimation an = new TranslateAnimation(type, 0, type, 0, type, 1, type, 0);
        an.setDuration(TRANSLATE_DURATION);
        return an;
    }

    /**
     * 销毁视图-透明度动画
     */
    private Animation createAlphaOutAnimation() {
        AlphaAnimation an = new AlphaAnimation(1, 0);
        an.setDuration(ALPHA_DURATION);
        an.setFillAfter(true);
        return an;
    }

    /**
     * 销毁视图-位移动画
     */
    private Animation createTranslationOutAnimation() {
        int type = TranslateAnimation.RELATIVE_TO_SELF;
        TranslateAnimation an = new TranslateAnimation(type, 0, type, 0, type, 0, type, 1);
        an.setDuration(TRANSLATE_DURATION);
        an.setFillAfter(true);
        an.setAnimationListener(new AnimationListener() {

            @Override
            public void onAnimationStart(Animation arg0) {
                // TODO Auto-generated method stub

            }

            @Override
            public void onAnimationRepeat(Animation arg0) {
                // TODO Auto-generated method stub

            }

            @Override
            public void onAnimationEnd(Animation arg0) {
                dismiss();
            }
        });
        return an;
    }

    /**
     * 底部按钮样式
     */
    private LinearLayout.LayoutParams createButtonLayoutParams() {
        return new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT,
                LayoutParams.WRAP_CONTENT);
    }

    /**
     * 自定义控件主题
     */
    private class Attributes {
        private Context mContext;
        private Drawable background;
        private Drawable cancelButtonBackground;
        private Drawable otherButtonTopBackground;
        private Drawable otherButtonMiddleBackground;
        private Drawable otherButtonBottomBackground;
        private Drawable otherButtonSingleBackground;
        private int cancelButtonTextColor;
        private int otherButtonTextColor;
        private int padding;
        private int otherButtonSpacing;
        private int cancelButtonMarginTop;
        private float actionSheetTextSize;

        Attributes(Context context) {
            this.mContext = context;
            background = new ColorDrawable(Color.TRANSPARENT);//背景透明
            cancelButtonBackground = new ColorDrawable(Color.BLACK);//取消按钮背景设置
            ColorDrawable gray = new ColorDrawable(Color.GRAY);
            this.otherButtonTopBackground = gray;
            this.otherButtonMiddleBackground = gray;
            this.otherButtonBottomBackground = gray;
            this.otherButtonSingleBackground = gray;
            this.cancelButtonTextColor = Color.WHITE;
            this.otherButtonTextColor = Color.BLACK;
            this.padding = dp2px(20);
            this.otherButtonSpacing = dp2px(2);
            this.cancelButtonMarginTop = dp2px(10);
            this.actionSheetTextSize = dp2px(16);
        }

        public Drawable getOtherButtonMiddleBackground() {
            if (otherButtonMiddleBackground instanceof StateListDrawable) { //类型判断
                TypedArray a = mContext.getTheme().obtainStyledAttributes(null, R.styleable.ActionSheet,
                        R.attr.actionSheetStyle, 0);
                otherButtonMiddleBackground = a
                        .getDrawable(R.styleable.ActionSheet_otherButtonMiddleBackground);
                a.recycle();
            }
            return otherButtonMiddleBackground;
        }

        //像素转换
        private int dp2px(int dp) {
            return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, mContext.getResources()
                    .getDisplayMetrics());
        }
    }

    //回调接口
    public interface MenuItemClickListener {
        void onItemClick(int position);
    }

}

最后一步,附上调用代码就完成了。

 ActionSheet actionSheet = new ActionSheet(this).setCancelableOnTouchMenuOutside(false).setCancelButtonTitle("退出");
        for (int i = 0; i < 3; i++) {
            actionSheet.addItem("第" + (i + 1) + "条", new ActionSheet.MenuItemClickListener() {
                @Override
                public void onItemClick(int position) {
                    Toast.makeText(MainActivity.this, "第" + (position + 1) + "条", Toast.LENGTH_SHORT).show();
                }
            });
        }
        actionSheet.showMenu();
相关标签: android

上一篇: 6.表连接

下一篇: 6. 使用taglist插件