Android GUI开发:PopUpWindow窗口

前言

Popwindow窗口是常见的控件之一,常常用于从屏幕下方弹出选择菜单。

简单的实现

在这里插入图片描述

1.PopUpWindow界面的XML

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="235dp"
        android:layout_alignParentBottom="true"
        android:background="#FFFFFFFF"
        android:orientation="vertical">

        <androidx.constraintlayout.widget.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="50dp">

            <TextView
                android:id="@+id/tv_menu_popwindow_cancel"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginStart="20dp"
                android:text="取消"
                android:textColor="#FF999999"
                android:textSize="18sp"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent" />

            <TextView
                android:id="@+id/tv_popwindow_title"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="请选择方式"
                android:textColor="#FF0F58A3"
                android:textSize="18sp"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent" />

            <TextView
                android:id="@+id/tv_menu_popwindow_agree"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginEnd="20dp"
                android:text="确认"
                android:textColor="#FF0F58A3"
                android:textSize="18sp"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintTop_toTopOf="parent" />
        </androidx.constraintlayout.widget.ConstraintLayout>

        <TextView
            android:id="@+id/tv_menu_popwindow_list1"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="45dp"
            android:background="#fff"
            android:gravity="center_horizontal"
            android:text="拍照"
            android:textColor="#FF0F58A3"
            android:textSize="24sp" />

        <TextView
            android:id="@+id/tv_menu_popwindow_list2"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:layout_marginTop="35dp"
            android:background="#fff"
            android:gravity="center_horizontal"
            android:text="从相册选择"
            android:textColor="#FF999999"
            android:textSize="22sp" />


    </LinearLayout>
</RelativeLayout>

2.继承PopupWindow

public class BottomMenuPopwindow extends PopupWindow implements View.OnClickListener {

    private TextView mTvTitle;
    private View mMenuView;
    private Activity mContext;
    
    public BottomMenuPopwindow(Activity context, String list1, String list2) {
        LayoutInflater inflater = LayoutInflater.from(context);
        mContext = context;
        mMenuView = inflater.inflate(R.layout.popwindow_camera_or_album, null);
        TextView btnCancel = mMenuView.findViewById(R.id.tv_menu_popwindow_cancel);
        TextView btnAgree = mMenuView.findViewById(R.id.tv_menu_popwindow_agree);
        TextView btnList1 = mMenuView.findViewById(R.id.tv_menu_popwindow_list1);
        TextView btnList2 = mMenuView.findViewById(R.id.tv_menu_popwindow_list2);
        mTvTitle = mMenuView.findViewById(R.id.tv_popwindow_title);
        btnList1.setText(list1);
        btnList2.setText(list2);
        btnCancel.setOnClickListener(this);
        btnList1.setOnClickListener(this);
        btnList2.setOnClickListener(this);
        btnAgree.setOnClickListener(this);
        setContentView(mMenuView);
        setWidth(ViewGroup.LayoutParams.MATCH_PARENT);
        setHeight(ViewGroup.LayoutParams.MATCH_PARENT);
        setFocusable(true);
        setAnimationStyle(R.style.bottom_menu_popwindow_anim_style);
        //注意  要是点击外部空白处弹框消息  那么必须给弹框设置一个背景色  不然是不起作用的
        setBackgroundDrawable(new BitmapDrawable());
        //点击外部消失
        setOutsideTouchable(true);
        //设置可以点击
        setTouchable(true);
    }

    /**
     * 显示菜单
     */
    public void show() {
        if (isShowing()) {
            dismiss();
        } else {
            setBackgroundAlpha(0.5f);
            showAtLocation(mMenuView, Gravity.BOTTOM, 0, 0);
        }

    }

    @Override
    public void dismiss() {
        super.dismiss();
        setBackgroundAlpha(1.0f);
    }


    public void setTvTitle(String title) {
        if (TextUtils.isEmpty(title)) {
            mTvTitle.setText(title);
        }
    }

    /**
     * 改变背景透明度
     *
     * @param alpha
     */
    private void setBackgroundAlpha(float alpha) {
        WindowManager.LayoutParams layoutParams = mContext.getWindow().getAttributes();
        layoutParams.alpha = alpha;
        mContext.getWindow().setAttributes(layoutParams);
    }


    public interface OnList1ClickListener {
        void onClick();
    }

    private OnList1ClickListener mOnList1ClickListener = null;

    public void setOnList1ClickListener(OnList1ClickListener listener) {
        mOnList1ClickListener = listener;
    }

    public interface OnList2ClickListener {
        void onClick();
    }

    private OnList2ClickListener mOnList2ClickListener = null;

    public void setOnList2ClickListener(OnList2ClickListener listener) {
        mOnList2ClickListener = listener;
    }


    @Override
    public void onClick(View view) {
        dismiss();
        switch (view.getId()) {
            case R.id.tv_menu_popwindow_cancel:
                break;
            case R.id.tv_menu_popwindow_agree:
            case R.id.tv_menu_popwindow_list1:
                if (mOnList1ClickListener != null) {
                    mOnList1ClickListener.onClick();
                }
                break;

            case R.id.tv_menu_popwindow_list2:
                if (mOnList2ClickListener != null) {
                    mOnList2ClickListener.onClick();
                }
                break;
        }
    }
}

其中showAtLocation(mMenuView, Gravity.BOTTOM, 0, 0);是控制PopUpWindow窗口出现的位置

showAtLocation(View parent, int gravity, int x, int y)
参数parent: 对弹窗的位置没有影响,主要作用获取windowtoken
参数gravity: 指定弹窗偏移方向的边缘
参数x: 坐标x方向的偏移
参数y: 坐标y方向的偏移

showAsDropDown(View anchor, int xoff, int yoff)
参数anchor: 弹窗依附的view
xoff : 坐标x方向的偏移 x+10表示向右偏移
yoff: 坐标y方向的偏移 y+10表示向下偏移

3.PopUpWindow出现动画

style.xml

    <style name="bottom_menu_popwindow_anim_style">
        <item name="android:windowEnterAnimation">@anim/pop_bottom_in</item>
        <!-- 指定显示的动画xml -->
        <item name="android:windowExitAnimation">@anim/pop_bottom_out</item>
        <!-- 指定消失的动画xml -->
    </style>

进场动画pop_bottom_in.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" >
    <translate
        android:duration="300"
        android:fromYDelta="100%p"
        android:toYDelta="0"
        />
    <alpha
        android:duration="300"
        android:fromAlpha="0.0"
        android:toAlpha="1.0" />

</set>

退场动画pop_bottom_out.xml

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

    <translate
        android:duration="300"
        android:fromYDelta="0"
        android:toYDelta="100%p" />
    <alpha
        android:duration="300"
        android:fromAlpha="1.0"
        android:toAlpha="0.0" />

</set>

4.在MainActivity中调用

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        BottomMenuPopwindow mMenuPopwindow = new BottomMenuPopwindow(MainActivity.this, "拍照", "从相册选择");
        mMenuPopwindow.setTvTitle("请选择方式");
        mMenuPopwindow.show();
    }
}

配合时间选择器

在这里插入图片描述

1.PopUpWindow界面的XML

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="260dp"
        android:layout_gravity="bottom"
        android:background="#FFFFFFFF"
        android:orientation="vertical">

        <androidx.constraintlayout.widget.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="50dp">

            <TextView
                android:id="@+id/tv_pop_scroll_selector_cancel"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginStart="20dp"
                android:text="取消"
                android:textColor="#FF999999"
                android:textSize="18sp"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent" />

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="请选择日期"
                android:textColor="#FF0F58A3"
                android:textSize="18sp"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent" />

            <TextView
                android:id="@+id/tv_pop_scroll_selector_agree"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginEnd="20dp"
                android:text="确认"
                android:textColor="#FF0F58A3"
                android:textSize="18sp"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintTop_toTopOf="parent" />
        </androidx.constraintlayout.widget.ConstraintLayout>

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="horizontal">

            <com.fenda.slock.ui.view.ScrollSelector
                android:id="@+id/pop_scroll_selector_year"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_weight="1">

            </com.fenda.slock.ui.view.ScrollSelector>

            <com.fenda.slock.ui.view.ScrollSelector
                android:id="@+id/pop_scroll_selector_month"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_weight="1">

            </com.fenda.slock.ui.view.ScrollSelector>

            <com.fenda.slock.ui.view.ScrollSelector
                android:id="@+id/pop_scroll_selector_day"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_weight="1">

            </com.fenda.slock.ui.view.ScrollSelector>

        </LinearLayout>
    </LinearLayout>
</LinearLayout>

2.滑动选择器的View

public class ScrollSelector extends View {

    /**
     * 获取选中项
     */
    public int getSelectedIndex() {
        return (int) (-offsetY + 0.5);
    }

    /**
     * 设置选中项
     */
    public void setSelectedIndex(int pos) {
        if (pos < 0 || pos >= contents.size()) {
            return;
        }
        offsetY = -pos + 1;
    }

    /**
     * 设置项列表的内容
     */
    public void setItemContents(ArrayList<String> list) {
        /*当前选中项为原本列表项的最后一项时,如果重新指定的列表项的比原本的列表项的小
          则会让当前的选中项为空,所以需要重新指定选中项*/
        if (getSelectedIndex() >= list.size()) {
            setSelectedIndex(list.size() - 1);
        }

        contents = list;
        invalidate();
    }

    /**
     * 设置显示的项数
     */
    public void setShowItemNum(int num) {
        showItemNum = num;
        offsetY = (showItemNum - 1) / 2;    //设置默认项
    }

    /**
     * 设置分割线的颜色
     */
    public void setDividerColor(int dividerColor) {
        this.dividerColor = dividerColor;
    }

    /**
     * 设置选中状态字体的颜色
     */
    public void setTextSelectorColor(int textSelectorColor) {
        this.textSelectorColor = textSelectorColor;
    }

    /**
     * 设置正常状态字体的颜色
     */
    public void setTextNormalColor(int textNormalColor) {
        this.textNormalColor = textNormalColor;
    }

    private final int DIVIDER_WIDTH = 0;        //分割线的宽度
    private final int DEFAULT_TEXTSIZE = DisplayUtil.sp2px(24);    //默认字体大小
    private final int SLEEP_TIME = 1000 / 60;   //动画的延时时间,每秒大约80帧
    private final int WHAT_INVALIDATE = 0;      //重新绘制

    private int showItemNum = 3;                    //显示的项数
    private int dividerY;                           //绘制分隔线的y坐标
    private int itemHeight;                         //每一项所占的高度
    private int dividerColor = 0x008A8A8A;          //分割线的颜色
    private int textSelectorColor = 0xFF0F58A3;     //选中状态文字的颜色
    private int textNormalColor = 0xFF999999;       //正常状态文字的颜色
    private int marqueeX;                           //跑马灯的x坐标偏移
    private int marqueeWidth;                       //跑马灯的宽度
    private int borderWhenDown;                     //按下时的边界状态
    private float offsetY;                          //项偏移的y坐标
    private boolean isPress;                        //手指是否是按下状态
    private boolean isFirst = true;                 //是否是首次绘制
    private boolean isSkiping;                      //是否正在执行跳转
    private boolean isStopSkiping;                  //是否要停止跳转
    private boolean isHoming;                       //是否正在执行归位
    private ArrayList<String> contents;             //项的内容
    private Paint mPaint;                           //画笔
    private GestureDetector mDetector;              //手势
    private Handler mHandler;                       //异步处理
    private RollThread rollThread;                  //滚动线程
    private MarqueeThread marqueeThread;            //跑马灯线程

    public ScrollSelector(Context context, AttributeSet attrs) {
        super(context, attrs);
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);                          //实例化画笔
        mPaint.setTextSize(DEFAULT_TEXTSIZE);                               //设置字体大小
        mPaint.setStrokeWidth(DIVIDER_WIDTH);                               //设置线条的宽度
        mDetector = new GestureDetector(context, new MyGestureListener());  //实例化手势
        contents = new ArrayList<>();                                       //初始化列表项的内容,防止出现空指针错误
        mHandler = new Handler() {                                           //实例化Handler
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                switch (msg.what) {
                    //重新绘制
                    case WHAT_INVALIDATE:
                        invalidate();
                        break;
                }
            }
        };
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        //计算每一项的高度
        itemHeight = h / showItemNum;

        //计算分割线的y坐标
        dividerY = itemHeight * ((showItemNum - 1) / 2);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        //绘制分割线
        mPaint.setColor(dividerColor);
        canvas.drawLine(0, dividerY, getWidth(), dividerY, mPaint);
        canvas.drawLine(0, dividerY + itemHeight, getWidth(), dividerY + itemHeight, mPaint);

        //边界限制
        borderLimit();

        //绘制项
        for (int i = 0; i < showItemNum + 1; i++) {
            //获取要绘制的项的序号
            int index = (int) -offsetY + i - (showItemNum - 1) / 2;
            if (index >= contents.size()) {
                break;
            }
            if (index < 0) {
                continue;
            }

            //获取字符串的宽高
            String item = contents.get(index);
            Rect bound = new Rect();
            mPaint.getTextBounds(item, 0, item.length(), bound);

            //绘制字符串
            int x = bound.width() > getWidth() ? 0 : (getWidth() - bound.width()) / 2;   //绘制文本的x坐标
            int y = (int) (itemHeight * i + (offsetY - (int) offsetY) * itemHeight);    //绘制文本的y坐标
            y += (itemHeight + bound.height()) / 2;                                     //绘制文本的基线偏移量

            if (getSelectedIndex() == index) {
                mPaint.setColor(textSelectorColor); //选中状态的字体颜色
                //判断是否需要跑马灯
                if (bound.width() > getWidth()) {
                    marqueeWidth = bound.width();
                    x = marqueeX;
                    if (isFirst) {
                        marquee();
                    }
                } else {
                    marqueeWidth = 0;
                }
            } else {
                mPaint.setColor(textNormalColor);   //正常状态的字体颜色
            }

            canvas.drawText(item, x, y, mPaint);

            if (isFirst) {
                isFirst = false;
            }
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        //手指按下
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            isPress = true;
            borderWhenDown = borderLimit();
            marqueeX = 0;
            if (isSkiping) {
                isStopSkiping = true;
            }
        }
        //手指抬起
        if (event.getAction() == MotionEvent.ACTION_UP) {
            isPress = false;
            if (!isSkiping) {
                homing();
            }
            marquee();
        }
        //手势判断
        mDetector.onTouchEvent(event);

        return true;
    }

    /**
     * 归位
     */
    private void homing() {
        if (isHoming) {
            return;
        }
        isHoming = true;
        new HomingThread().start();
    }

    /**
     * 滚动
     */
    private void roll(float speed) {
        if (rollThread != null && rollThread.isAlive()) {
            return;
        }

        rollThread = new RollThread(speed);
        rollThread.start();
    }

    /**
     * 跳转
     *
     * @param dir true为跳转到顶部,false为跳转到底部
     */
    private void skip(boolean dir) {
        if (isSkiping) {
            return;
        }
        isSkiping = true;
        Log.e("tag", "skip");
        new SkipThread(dir).start();
    }

    /**
     * 跑马灯显示
     */
    private void marquee() {
        if (marqueeThread != null && marqueeThread.isAlive()) {
            return;
        }

        marqueeThread = new MarqueeThread();
        marqueeThread.start();
    }

    /**
     * 边界限制
     *
     * @return -1为在顶部,1为在底部,0为不在边界
     */
    private int borderLimit() {
        if (offsetY >= 0) {                          //顶部边界
            offsetY = 0;
            return -1;
        } else if (offsetY <= -contents.size() + 1) {   //底部边界
            offsetY = -contents.size() + 1;
            return 1;
        }
        return 0;
    }

    /**
     * 手势事件
     */
    private class MyGestureListener extends GestureDetector.SimpleOnGestureListener {

        /**
         * 滑动
         */
        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
            int border = borderLimit();
            if (borderWhenDown == -1 && border == -1 && distanceY < 0) {         //跳转到底部
                skip(false);
            } else if (borderWhenDown == 1 && border == 1 && distanceY > 0) {    //跳转到顶部
                skip(true);
            } else if (!isSkiping) {
                offsetY -= distanceY / itemHeight;      //偏移量
                invalidate();
            }

            return false;
        }

        /**
         * 滚动
         */
        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
            float speed = velocityY / itemHeight / 20;
            if (Math.abs(speed) > 0.5) {
                roll(speed);
            }
            return super.onFling(e1, e2, velocityX, velocityY);
        }
    }

    /**
     * 自动返回中间位置的(归位)线程
     */
    private class HomingThread extends Thread {

        private final float MOVE_DISTANCE = 0.05f;   //每一帧的移动距离(itemHeight的比例)

        @Override
        public void run() {
            super.run();

            float dy = 0;
            while (!isPress) {    //手指按下就停止归位
                //取小数部分
                float decimal = Math.abs(offsetY - (int) offsetY);
                //大概达到中间位置
                if (decimal > -MOVE_DISTANCE * 1.1 && decimal < MOVE_DISTANCE * 1.1) {
                    break;
                }
                //移动量
                dy = decimal < 0.5 ? MOVE_DISTANCE : -MOVE_DISTANCE;
                //防止超过位置
                if ((int) offsetY != (int) (offsetY + dy)) {
                    break;
                }

                offsetY += dy;

                try {
                    Thread.sleep(SLEEP_TIME);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //重新绘制
                mHandler.sendEmptyMessage(WHAT_INVALIDATE);
            }
            //取整
            if (!isPress) {
                offsetY = (int) offsetY;
                if (dy < 0) {   //误差校正
                    offsetY--;
                }
                mHandler.sendEmptyMessage(WHAT_INVALIDATE);
            }
            isHoming = false;
        }
    }

    /**
     * 滚动的线程
     */
    private class RollThread extends Thread {

        private final float DAMPING = 0.1f;    //速度的衰减,即每一帧之后的衰减量

        private float speed;        //滚动的速度,即每一帧移动的距离

        public RollThread(float speed) {
            this.speed = speed;
        }

        @Override
        public void run() {
            super.run();

            boolean dir = speed > 0;   //滚动方向,true为向上,false为向下
            while (!isPress) {
                offsetY += speed;
                //显示越界
                if (borderLimit() != 0) {
                    mHandler.sendEmptyMessage(WHAT_INVALIDATE);
                    break;
                }
                //速度衰减
                speed += (dir ? -DAMPING : DAMPING);
                //速度越界
                if ((dir && speed < 0) || (!dir && speed > 0)) {
                    break;
                }

                try {
                    Thread.sleep(SLEEP_TIME);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //重新绘制
                mHandler.sendEmptyMessage(WHAT_INVALIDATE);
            }
            //滚动完后归位
            if (!isPress) {
                homing();
            }
        }
    }

    /**
     * 顶部和底部的跳转
     */
    private class SkipThread extends Thread {

        private final float SKIP_TIME = 1000;    //跳转时间,1秒

        private boolean dir;    //true为跳转到顶部,false为跳转到底部

        public SkipThread(boolean dir) {
            this.dir = dir;
        }

        @Override
        public void run() {
            super.run();

            float framesNum = SKIP_TIME / SLEEP_TIME;     //总帧数
            float speed = (contents.size()) / framesNum;    //每帧移动的距离
            if (!dir) {
                speed *= -1;
            }

            while (!isStopSkiping && getSelectedIndex() != (dir ? 0 : contents.size() - 1)) {
                offsetY += speed;

                try {
                    Thread.sleep(SLEEP_TIME);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                mHandler.sendEmptyMessage(WHAT_INVALIDATE);
            }
            if (!isPress) {
                homing();
            }
            isSkiping = false;
            isStopSkiping = false;
        }
    }

    /**
     * 过长文字跑马灯显示的线程
     */
    private class MarqueeThread extends Thread {

        private final int moveDistance = 3;    //每一帧的移动距离

        @Override
        public void run() {
            super.run();

            while (!isPress && marqueeWidth != 0) {
                marqueeX -= moveDistance;

                if (marqueeX < -marqueeWidth) {
                    marqueeX = getWidth();
                }

                try {
                    Thread.sleep(SLEEP_TIME);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                mHandler.sendEmptyMessage(WHAT_INVALIDATE);
            }
        }
    }
}

3.继承PopupWindow

public class SrollSelectorTimePop extends PopupWindow implements View.OnClickListener {


    private TextView mBtnCancel, mBtnAgree;
    private View mMenuView;
    private Activity mContext;
    //滚动选择器
    private ScrollSelector scrollSelectorYear;
    private ScrollSelector scrollSelectorMonth;
    private ScrollSelector scrollSelectorDay;
    private ArrayList<String> yearList;
    private ArrayList<String> monthList;
    private ArrayList<String> dayList;

    public SrollSelectorTimePop(Activity context) {
        LayoutInflater inflater = LayoutInflater.from(context);
        mContext = context;
        mMenuView = inflater.inflate(R.layout.popwidow_sroll_selector, null);
        mBtnCancel = mMenuView.findViewById(R.id.tv_pop_scroll_selector_cancel);
        mBtnAgree = mMenuView.findViewById(R.id.tv_pop_scroll_selector_agree);
        //获取滚动选择器控件
        scrollSelectorYear = mMenuView.findViewById(R.id.pop_scroll_selector_year);
        scrollSelectorMonth = mMenuView.findViewById(R.id.pop_scroll_selector_month);
        scrollSelectorDay = mMenuView.findViewById(R.id.pop_scroll_selector_day);
        mBtnCancel.setOnClickListener(this);
        mBtnAgree.setOnClickListener(this);
        setContentView(mMenuView);
        setWidth(ViewGroup.LayoutParams.MATCH_PARENT);
        setHeight(ViewGroup.LayoutParams.MATCH_PARENT);
        setFocusable(true);
        setAnimationStyle(R.style.bottom_menu_popwindow_anim_style);
        //注意  要是点击外部空白处弹框消息  那么必须给弹框设置一个背景色  不然是不起作用的
        setBackgroundDrawable(new BitmapDrawable());
        //点击外部消失
        setOutsideTouchable(true);
        //设置可以点击
        setTouchable(true);
        currentTime();
        yearList = getYearList();
        monthList = getMonthList();
        dayList = getDayList();
    }


    /**
     * 显示菜单
     */
    public void show() {
        if (isShowing()) {
            dismiss();
        } else {
            //设置滚动选择器的项列表
            scrollSelectorYear.setItemContents(yearList);
            scrollSelectorMonth.setItemContents(monthList);
            scrollSelectorDay.setItemContents(dayList);
            setBackgroundAlpha(0.5f);
            showAtLocation(mMenuView, Gravity.BOTTOM, 0, 0);
        }
    }


    @Override
    public void dismiss() {
        super.dismiss();
        setBackgroundAlpha(1.0f);
    }

    /**
     * 改变背景透明度
     *
     * @param alpha
     */
    private void setBackgroundAlpha(float alpha) {
        WindowManager.LayoutParams layoutParams = ((Activity)
                mContext).getWindow().getAttributes();
        layoutParams.alpha = alpha;
        ((Activity) mContext).getWindow().setAttributes(layoutParams);
    }

    private void currentTime() {
        Calendar calendar = Calendar.getInstance();
        //获取系统的日期
        //年
        int year = calendar.get(Calendar.YEAR);
        //月
        int month = calendar.get(Calendar.MONTH) + 1;
        //日
        int day = calendar.get(Calendar.DAY_OF_MONTH);
        scrollSelectorYear.setSelectedIndex(year - 2019);
        scrollSelectorMonth.setSelectedIndex(month - 1);
        scrollSelectorDay.setSelectedIndex(day - 1);
    }

    private ArrayList<String> getYearList() {
        ArrayList<String> yearList = new ArrayList<>();
        for (int a = 2019; a < 2049; a++) {
            yearList.add(a + "");
        }
        return yearList;
    }

    private ArrayList<String> getMonthList() {
        ArrayList<String> monthList = new ArrayList<>();
        for (int a = 1; a < 13; a++) {
            monthList.add(a + "");
        }
        return monthList;
    }

    private ArrayList<String> getDayList() {
        ArrayList<String> dayList = new ArrayList<>();
        for (int a = 1; a < 32; a++) {
            dayList.add(a + "");
        }
        return dayList;
    }

    public interface OnAgreeClickListener {
        void onClick(String year, String month, String day);
    }

    private OnAgreeClickListener mOnAgreeClickListener = null;

    public void setAgreeOnClickListener(OnAgreeClickListener listener) {
        mOnAgreeClickListener = listener;
    }


    @Override
    public void onClick(View view) {
        dismiss();
        switch (view.getId()) {
            case R.id.tv_pop_scroll_selector_cancel:
                break;
            case R.id.tv_pop_scroll_selector_agree:
                String year = yearList.get(scrollSelectorYear.getSelectedIndex());
                String month = monthList.get(scrollSelectorMonth.getSelectedIndex());
                String day = dayList.get(scrollSelectorDay.getSelectedIndex());
                if (mOnAgreeClickListener != null) {
                    mOnAgreeClickListener.onClick(year, month, day);
                }
                break;
        }
    }
}

4.出场动画

参考上面

5.在MainActivity中调用

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        SrollSelectorTimePop mSrollSelectorTimePop = new SrollSelectorTimePop(this);
        mSrollSelectorTimePop.setAgreeOnClickListener((year, month, day) -> {
           String unLockDate = year + "/" + month + "/" + day;
           LogUtil.i(unLockDate);
        });
    }
}
发布了63 篇原创文章 · 获赞 1 · 访问量 2101

猜你喜欢

转载自blog.csdn.net/weixin_42046829/article/details/104490586