仿IOS底部弹出框

仿IOS底部弹出框

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

首先是资源类drawable
在这里插入图片描述在这里插入图片描述
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>

至此,枯燥的资源类已经全部完成,接下来是定义主题样式
在这里插入图片描述
相关的两个文件放在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 View.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;

    private int paddingTop = 0;

    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(LayoutParams.MATCH_PARENT,
                LayoutParams.MATCH_PARENT);
        //  parentParams.gravity = Gravity.BOTTOM;
        parent.setLayoutParams(parentParams);
        mBg = new View(mContext);
        mBg.setLayoutParams(new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
        mBg.setBackgroundColor(Color.argb(136, 0, 0, 0));
        mBg.setId(BG_VIEW_ID);
        mBg.setOnClickListener(this);

        final ScrollView scrollView = new ScrollView(mContext);
        FrameLayout.LayoutParams mPanelParams = new FrameLayout.LayoutParams(
                LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
        mPanelParams.gravity = Gravity.BOTTOM;
        scrollView.setLayoutParams(mPanelParams);
        scrollView.setVerticalScrollBarEnabled(false);

        mPanel = new LinearLayout(mContext);
        mPanel.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
        ScrollView.LayoutParams layoutParams = new ScrollView.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
        mPanel.setLayoutParams(layoutParams);
        mPanel.setOrientation(LinearLayout.VERTICAL);

        scrollView.addView(mPanel);
        parent.addView(mBg);
        parent.addView(scrollView);

        mPanel.post(new Runnable() {
            @Override
            public void run() {
                paddingTop = scrollView.getHeight() - mPanel.getHeight();
                if (paddingTop > 0) {
                    mPanel.setPadding(mAttrs.padding, paddingTop + mAttrs.padding, mAttrs.padding, mAttrs.padding);
                } else {
                    mPanel.setPadding(mAttrs.padding, mAttrs.padding, mAttrs.padding, mAttrs.padding);
                }
            }
        });

        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(ViewGroup.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);
        if (paddingTop > 0) {
            mPanel.setPadding(mAttrs.padding, paddingTop + mAttrs.padding, mAttrs.padding, mAttrs.padding);
        } else {
            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 Animation.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(ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.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();
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值