【需求】:弹出一个非全屏窗口,可以选择时间设置,文本输入; 看似简单确认折腾了一天多时间,下面把实战经历记录如下。

【实现思路及方法】:有两种,一种是通过Dialog实现,一种是通过Popupwindow实现,两者的实现思路差别不大,主要是遇到的问题各有千秋。

一、通过继承Dialog实现

1、编辑界面文件

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

2、自定义Dialog类,继承自Dialog

主要思路:

1)可以看到界面中定义了两个按钮,外层创建Dialog对象时,构造函数中直接传入点击事件的监听器,并开启监听。监听器可以在外层自己定义,监听两个按键的动作,外层直接执行不同 的操作;

2)时间选择/模式选择分别使用TimePickerView 、OptionsPickerView,点击各自的文本时会在底部弹出时间选择器,选项选择器;

public class MineClockEditPop extends Dialog {    private Activity mContext;    private View.OnClickListener mClickListener;    private Button buttonCancel;    private Button buttonSave;    public EditText editTime;    public EditText editMode;    public EditText editNote;    public MineClockEditPop(Activity context) {        super(context);        this.mContext = mContext;    }    public MineClockEditPop(Activity context, int theme, View.OnClickListener clickListener) {        super(context, theme);        this.mContext = context;        this.mClickListener = clickListener;    }    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        this.setContentView(R.layout.tab_mine_clock_edit);        editTime = (EditText) findViewById(R.id.clock_edit_time);        editMode = (EditText) findViewById(R.id.clock_edit_mode);        editNote = (EditText) findViewById(R.id.clock_edit_note);        buttonCancel =  (Button) findViewById(R.id.clock_edit_cancel);        buttonSave = (Button) findViewById(R.id.clock_edit_save);        // 设置弹出窗体的宽和高        /*         * 获取窗口对象及参数对象以修改对话框的布局设置, 可以直接调用getWindow(),表示获得这个Activity的Window         * 对象,这样这可以以同样的方式改变这个Activity的属性.         */        Window dialogWindow = this.getWindow();        WindowManager m = mContext.getWindowManager();        Display d = m.getDefaultDisplay(); // 获取屏幕宽、高用        WindowManager.LayoutParams p = dialogWindow.getAttributes(); // 获取对话框当前的参数值        p.width = (int) (d.getWidth() * 0.8);        dialogWindow.setAttributes(p);        dialogWindow.setGravity(Gravity.CENTER_VERTICAL);        // 设置按钮监听        buttonCancel.setOnClickListener(mClickListener);        buttonSave.setOnClickListener(mClickListener);        this.setCancelable(false);         //自定义时间选择器        editTime.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View view) {                TimePickerView mTimePickerView = new TimePickerView(mContext, TimePickerView.Type.HOURS_MINS);                // 设置是否循环                mTimePickerView.setCyclic(true);                // 设置滚轮文字大小                mTimePickerView.setTitle("选择时间");                mTimePickerView.setTextSize(TimePickerView.TextSize.SMALL);                // 设置时间可选范围(结合 setTime 方法使用,必须在)//                Calendar calendar = Calendar.getInstance();//                mTimePickerView.setRange(calendar.get(Calendar.YEAR) - 100, calendar.get(Calendar.YEAR));                // 设置选中时间                mTimePickerView.setTime(new Date());                mTimePickerView.setOnTimeSelectListener(new TimePickerView.OnTimeSelectListener() {                    @Override                    public void onTimeSelect(Date date) {                        SimpleDateFormat format = new SimpleDateFormat("HH:mm", Locale.CHINA);//                Toast.makeText(MineInformationActivity.this, format.format(date), Toast.LENGTH_SHORT).show();                        editTime.setText(format.format(date));                    }                });                mTimePickerView.show();            }        });        //自定义模式选择器        editMode.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View view) {                OptionsPickerView mOptionsPickerView = new OptionsPickerView<>(mContext);                final ArrayList list = new ArrayList<>();                list.add("仅一次");                list.add("每天");                mOptionsPickerView.setTitle("选择模式");                // 设置数据                mOptionsPickerView.setPicker(list);                // 设置选项单位                mOptionsPickerView.setOnOptionsSelectListener(new OptionsPickerView.OnOptionsSelectListener() {                    @Override                    public void onOptionsSelect(int option1, int option2, int option3) {                        String mode = list.get(option1);//                Toast.makeText(MineInformationActivity.this, sex, Toast.LENGTH_SHORT).show();                        editMode.setText(mode);                    }                });                mOptionsPickerView.show();            }        });    }}

3、外部调用层 自定义窗口中按钮点击事件监听器

//自定义按钮监听事件    private View.OnClickListener onClickListener = new View.OnClickListener() {        @Override        public void onClick(View v) {            switch (v.getId()) {                case R.id.clock_edit_cancel:                    break;                case R.id.clock_edit_save:                    String time = clockEditPop.editTime.getText().toString().trim();                    String mode = clockEditPop.editMode.getText().toString().trim();                    String note = clockEditPop.editNote.getText().toString().trim();                    LogUtil.d(TAG,time+"---"+mode+"---"+note);                    clockEditPop.dismiss();                    break;            }        }    };

4、调用:
        clockEditPop = new MineClockEditPop(this,1,onClickListener);
        clockEditPop.show();

5、总结

使用这个方法存在的问题是,我在Dialog中使用了TimePickerView 、OptionsPickerView,这俩本质上是个Popupwindow,点击出现时没有出现在Dialog的顶层,而是在其下层,这样用户无法选中时间或者选项了,如果需求中没有用的这俩东西,只是普通的文本输入,用这个方法是没问题的。

Android——弹出窗口中实现时间选择,文本输入,遇到Popupwindow不穿透与EditText输入法的矛盾,Dialog中弹出pop的显示层级问题_第1张图片

关于无法解决POP 窗口在dialog下面的问题,请路过的兄弟帮忙指点下,多谢!

二、通过继承PopupWindow实现

1、编辑界面,如一,不再赘述

2、Popup窗口类,继承自PopupWindow,外部调用层 自定义窗口中按钮点击事件监听器

思路与一中基本一致,只是构造函数处有略微差别。不再赘述。

public class MineClockEditPop extends PopupWindow {    private Context mContext;    private View view;    private Button buttonCancel;    private Button buttonSave;    public EditText editTime;    public EditText editMode;    public EditText editNote;    //构造函数,外部调用时传入自定义的监听器    public MineClockEditPop(final Activity mContext, View.OnClickListener itemsOnClick) {        this.mContext = mContext;        this.view = LayoutInflater.from(mContext).inflate(R.layout.tab_mine_clock_edit, null);        editTime = (EditText) view.findViewById(R.id.clock_edit_time);        editMode = (EditText) view.findViewById(R.id.clock_edit_mode);        editNote = (EditText) view.findViewById(R.id.clock_edit_note);        buttonCancel =  (Button) view.findViewById(R.id.clock_edit_cancel);        buttonSave = (Button) view.findViewById(R.id.clock_edit_save);        // 设置按钮监听        buttonCancel.setOnClickListener(itemsOnClick);        buttonSave.setOnClickListener(itemsOnClick);        // 设置外部可点击,即点击pop窗口外pop消失        this.setOutsideTouchable(false);        /* 设置弹出窗口特征 */        // 设置视图        this.setContentView(this.view);        // 设置弹出窗体的宽和高        /*         * 获取窗口对象及参数对象以修改对话框的布局设置, 可以直接调用getWindow(),表示获得这个Activity的Window         * 对象,这样这可以以同样的方式改变这个Activity的属性.         */        Window dialogWindow = mContext.getWindow();        WindowManager m = mContext.getWindowManager();        Display d = m.getDefaultDisplay(); // 获取屏幕宽、高用        WindowManager.LayoutParams p = dialogWindow.getAttributes(); // 获取对话框当前的参数值        this.setHeight(RelativeLayout.LayoutParams.WRAP_CONTENT);        this.setWidth((int) (d.getWidth() * 0.8));        // 设置聚焦,否则EditText输入法无响应        this.setFocusable(false);        //自定义时间选择器        editTime.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View view) {                TimePickerView mTimePickerView = new TimePickerView(view.getContext(), TimePickerView.Type.HOURS_MINS);                // 设置是否循环                mTimePickerView.setCyclic(true);                // 设置滚轮文字大小                mTimePickerView.setTitle("选择时间");                mTimePickerView.setTextSize(TimePickerView.TextSize.SMALL);                // 设置时间可选范围(结合 setTime 方法使用,必须在)//                Calendar calendar = Calendar.getInstance();//                mTimePickerView.setRange(calendar.get(Calendar.YEAR) - 100, calendar.get(Calendar.YEAR));                // 设置选中时间                mTimePickerView.setTime(new Date());                mTimePickerView.setOnTimeSelectListener(new TimePickerView.OnTimeSelectListener() {                    @Override                    public void onTimeSelect(Date date) {                        SimpleDateFormat format = new SimpleDateFormat("HH:mm", Locale.CHINA);//                Toast.makeText(MineInformationActivity.this, format.format(date), Toast.LENGTH_SHORT).show();                        editTime.setText(format.format(date));                    }                });                mTimePickerView.show();            }        });        //自定义模式选择器        editMode.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View view) {                OptionsPickerView mOptionsPickerView = new OptionsPickerView<>(view.getContext());                final ArrayList list = new ArrayList<>();                list.add("仅一次");                list.add("每天");                mOptionsPickerView.setTitle("选择模式");                // 设置数据                mOptionsPickerView.setPicker(list);                // 设置选项单位                mOptionsPickerView.setOnOptionsSelectListener(new OptionsPickerView.OnOptionsSelectListener() {                    @Override                    public void onOptionsSelect(int option1, int option2, int option3) {                        String mode = list.get(option1);//                Toast.makeText(MineInformationActivity.this, sex, Toast.LENGTH_SHORT).show();                        editMode.setText(mode);                    }                });                mOptionsPickerView.show();            }        });        editNote.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View view) {                //设置Popupwindow的setFocusable  为true,可以输入文本                //MineClockEditPop.this.setFocusable(false);                //手动弹出输入法                InputMethodManager inputMethodManager = (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE);                inputMethodManager.toggleSoftInput(0,InputMethodManager.HIDE_NOT_ALWAYS);//                editNote.setFocusableInTouchMode(true);//                editNote.setFocusable(true);//                editNote.requestFocus();            }        });    }}

3、调用:

//调用
        clockEditPop = new MineClockEditPop(this,onClickListener);
        clockEditPop.showAtLocation(findViewById(R.id.tab_mine_clock), Gravity.CENTER, 0, 0);

4、总结

1)使用这个方法存在的问题是,我想让自定义的Popup窗口不穿透,即点击窗口外时,这个Popup窗口不消失(弹出实现选择器和选项选择器的需求),这时要设置的两个属性,关于为什么要设置第二个可以看下第一个属性起作用的条件,如下截图,那就是setFocusable 为false。

// 设置外部可点击,即点击pop窗口外pop消失        this.setOutsideTouchable(false);// 设置聚焦,否则EditText输入法无响应        this.setFocusable(false);

Android——弹出窗口中实现时间选择,文本输入,遇到Popupwindow不穿透与EditText输入法的矛盾,Dialog中弹出pop的显示层级问题_第2张图片 

2)第一个问题解决了, setFocusable(false) 却带来了第二个问题,我的文本框没法输入了,输入法也不出现,因为没有聚焦。我尝试在文本点击时手动弹出输入法,在点击事件匿名类中调用上层类的方法,修改setFocusable属性,但是都不起作用,最后还是没有解决,这个水火不容的大BUG。

关于无法解决自定义Popup不穿透及EditText输入文本矛盾的问题,请路过的兄弟指点,多谢!

三、最终变相解决方法

基于Pop的方案的输入法问题实在没法解决,又把目标转向了基于Dialog的方案,这个方案的瑕疵在在于从Dialog弹出时间选择器的界面层级问题,Dialog都是显示在最顶层的,所以把TimerPickerView换成了TimerPickerDialog,最终完美解决,选项选择器换成combox了,就不再给出代码了。

Android——弹出窗口中实现时间选择,文本输入,遇到Popupwindow不穿透与EditText输入法的矛盾,Dialog中弹出pop的显示层级问题_第3张图片Android——弹出窗口中实现时间选择,文本输入,遇到Popupwindow不穿透与EditText输入法的矛盾,Dialog中弹出pop的显示层级问题_第4张图片

Calendar calendar = Calendar.getInstance();                //create a datePickerDialog and then shoe it on your screen                new TimePickerDialog(mContext,                        new TimePickerDialog.OnTimeSetListener() {                            @Override                            public void onTimeSet(TimePicker view, int hourOfDay, int minute) {                                DecimalFormat df = new DecimalFormat("00");                                df.setRoundingMode(RoundingMode.HALF_DOWN);                                editTime.setText(df.format(hourOfDay)+":"+df.format(minute));                            }                        }                        , calendar.get(Calendar.HOUR_OF_DAY)                        , calendar.get(Calendar.MINUTE)                        , true).show();

更多相关文章

  1. Android中 完美实现 计时 倒计时 时间间隔处理等功能实现 by Cou
  2. android 笔记 --- 让Android的输入框与文本框带滚动条ScrollView
  3. android 仿课程表,时间星期展示选择列表,简单易懂
  4. android中获得系统的时间
  5. android 时间1
  6. android之EditText文本监听(addTextChangedListener)
  7. android html超链接文本 点击跳转的两种实现
  8. android 自定义toast停留时间
  9. Android 输入法详解

随机推荐

  1. 1. 实例演示Ajax的get,post请求; 2. 练习
  2. html表格作业
  3. <JVM下篇:性能监控与调优篇>03-JVM监控及
  4. 返回数组中所有的值并给其建立从0开始递
  5. 返回数组中所有的值并给其建立从0开始递
  6. 0629作业
  7. 基于云原生日志分类处理方案与落地实践
  8. 字体图标 盒模型作业
  9. flex布局:flex容器中的四个属性的功能,参数
  10. 0629作业