Android自定义简易时间选择器

本文介绍如何创建一个自定义的时间选择器,该选择器由三个可滑动的列表视图组成,分别显示年份、月份和日期。当停止滑动时,选择的日期会居中显示。通过详细讲解布局设计和代码实现,展示了如何实现这一功能。提供了一个完整的Demo下载链接。

首先,我们来看下这个时间选择器大概的样子


我们来仔细观察下这个布局,在选择日期的时候,我们可以看做是可以上下滑动的三个listview的横向组合,listview的内容则是年份,月份和日期。

然后这个选择器中可见的是3个item,中间显示的才是我们要选定的日期。

来看下功能,比如说现在我们要选择年份,当我们停止滑动年份的这个选择器的时候,选择器会停下来并且会把我们所想选择的年份居中显示。

好了,现在我们来开始写这个选择器的布局吧。

这个是我们的首页






    

接下来就是我们的日期选择器的界面啦!




    

    

        

        

            

            

            
        
    

    

        

我们可以看到这个时间选择器上的listview的可见的item是有三个,那么这样如何实现呢,我们可以把listview的高度设成固定值,其item的高度就设置成listview高度的1/3,就可以啦!不多说,上代码:







好啦,布局我们有了可以上代码了

首先是我们的日期选择器的代码,具体我在这不多说了,代码里有很详细的注解


package com.example.peiwc.myapplicationtime;

import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;


public class CustomDialog extends Dialog {
    public CustomDialog(Context context, int theme) {
        super(context, theme);
    }

    public static class Builder {
        private int year;
        private int month;
        private int day;
        int y;
        private Context context;
        private DialogInterface.OnClickListener positiveButtonClickListener;
        private DialogInterface.OnClickListener negativeButtonClickListener;
        private ArrayList year_list, mouth_list, day_list;
        ListView lv1, lv2, lv3;

        public Builder(Context context) {
            this.context = context;
        }

        public Builder setPositiveButton(DialogInterface.OnClickListener listener) {
            this.positiveButtonClickListener = listener;
            return this;
        }

        public Builder setNegativeButton(DialogInterface.OnClickListener listener) {
            this.negativeButtonClickListener = listener;
            return this;
        }

        public CustomDialog create() {
            //创建日期选择器界面
            LayoutInflater inflater = (LayoutInflater) context
                    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            final CustomDialog dialog = new CustomDialog(context, R.style.Dialog);
            View layout = inflater.inflate(R.layout.time_dialog, null);
            dialog.addContentView(layout, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
            if (positiveButtonClickListener != null) {
                layout.findViewById(R.id.sure).setOnClickListener(new View.OnClickListener() {
                    public void onClick(View v) {
                        positiveButtonClickListener.onClick(dialog,
                                DialogInterface.BUTTON_POSITIVE);
                    }
                });
            }

            if (negativeButtonClickListener != null) {
                layout.findViewById(R.id.cancel)
                        .setOnClickListener(new View.OnClickListener() {
                            public void onClick(View v) {
                                negativeButtonClickListener.onClick(dialog,
                                        DialogInterface.BUTTON_NEGATIVE);
                            }
                        });
            }
            lv1 = (ListView) layout.findViewById(R.id.lv1);//年listview
            lv2 = (ListView) layout.findViewById(R.id.lv2);//月listview
            lv3 = (ListView) layout.findViewById(R.id.lv3);//日listview
            initListViews();
            dialog.setContentView(layout);
            return dialog;
        }

        private void initListViews() {

            Calendar calendar = Calendar.getInstance();
            //获得当前的日期
            year = calendar.get(Calendar.YEAR);
            month = calendar.get(Calendar.MONTH) + 1;
            day = calendar.get(Calendar.DAY_OF_MONTH);
            y = year - 2000 + 1;//这个y是从2000年到当前年份2016年中间间隔的年数,17年,这个可以看需求自己定
            year_list = new ArrayList();
            mouth_list = new ArrayList();
            day_list = new ArrayList();
            getContent(year_list, mouth_list, day_list);
            lv1.setAdapter(new MyAdapter( year_list));
            lv1.setSelection(year_list.size() - 3);//默认年份现实的是今年的年份,因为年份list最后一位是“”,当前年份是倒数第二位,即lv1.setSelection(year_list.size() - 3)显示的是当前的年份
            //给listview设置滚动监听,当滚动停止后让listview显示特定的一项
            lv1.setOnScrollListener(new AbsListView.OnScrollListener() {

                @Override
                public void onScrollStateChanged(AbsListView view, int scrollState) {
                    switch (scrollState) {
                        case AbsListView.OnScrollListener.SCROLL_STATE_IDLE://空闲状态
                            //获得当滑动结束后listview可见的第0个item的滚动距离
                            int a = 0 - lv1.getChildAt(0).getTop();
                            //获得listview的每个item的高度
                            int b = lv1.getMeasuredHeight() / 3;
                            float f = (float) a / b;
                            //如果滑动出屏幕的item的大小占item大小的比重在0到0.75之间的话,显示第一个可见的,就是说如果移动范围小的话显示的日期是不变的
                            if (f < 0.75) {
                                lv1.setSelection(lv1.getFirstVisiblePosition());
                            }
                            //如果滑动出屏幕的item的大小占item大小的比重在0。75到1之间的话,显示第二个可见的,就是说如果移动范围大的话显示的日期是要加一的
                            if (f > 0.75 && f < 1) {
                                lv1.setSelection(lv1.getFirstVisiblePosition() + 1);
                            }
                    }
                }

                @Override
                public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {

                }
            });
            //显示月份同上
            lv2.setAdapter(new MyAdapter( mouth_list));
            lv2.setSelection(calendar.get(Calendar.MONTH));
            lv2.setOnScrollListener(new AbsListView.OnScrollListener() {
                @Override
                public void onScrollStateChanged(AbsListView view, int scrollState) {
                    switch (scrollState) {
                        case AbsListView.OnScrollListener.SCROLL_STATE_IDLE://空闲状态

                            int a = 0 - lv2.getChildAt(0).getTop();
                            int b = lv2.getMeasuredHeight() / 3;
                            float f = (float) a / b;
                            if (f < 0.75) {
                                lv2.setSelection(lv2.getFirstVisiblePosition());
                            }
                            if (f > 0.75 && f < 1) {
                                lv2.setSelection(lv2.getFirstVisiblePosition() + 1);
                            }
                    }
                }
                @Override
                public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {

                }
            });
            //显示日期同上
            lv3.setAdapter(new MyAdapter( day_list));
            lv3.setSelection(day - 1);
            lv3.setOnScrollListener(new AbsListView.OnScrollListener() {
                @Override
                public void onScrollStateChanged(AbsListView view, int scrollState) {
                    switch (scrollState) {
                        case AbsListView.OnScrollListener.SCROLL_STATE_IDLE://空闲状态

                            int a = 0 - lv3.getChildAt(0).getTop();
                            int b = lv3.getMeasuredHeight() / 3;
                            float f = (float) a / b;
                            if (f < 0.75) {
                                lv3.setSelection(lv3.getFirstVisiblePosition());
                            }
                            if (f > 0.75 && f < 1) {
                                lv3.setSelection(lv3.getFirstVisiblePosition() + 1);
                            }
                    }
                }

                @Override
                public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {

                }
            });
        }

        /**
         * 给选择器添加内容
         */
        private void getContent(List year_list, List mouth_list, List day_list) {
            //因为选择器是分3格,中间显示的数字才算是时间,拉到最上方和最下方的时候都要留白,所以要赋值的话list前后要填加“”,
            //所以年份的list的长度是y+2,月份的长度是12+2=14,日期的话就是31+2=33。
            String my;
            for (int i = 0; i < y + 2; i++) {
                if (i == 0 || i == y + 1) {
                    my = "";
                } else {
                    int m = 2000 + i - 1;
                    my = String.valueOf(m);
                }
                year_list.add(i, my);
            }
            String mm;
            for (int i = 0; i < 14; i++) {
                if (i == 0 || i == 13) {
                    mm = "";
                } else {
                    mm = i + "";
                }
                mouth_list.add(i, mm);
            }
            String md;
            for (int i = 0; i < 33; i++) {
                if (i == 0 || i == 32) {
                    md = "";
                } else {
                    md = i + "";
                }
                day_list.add(i, md);
            }
        }

        public String getStr() {
            int year = lv1.getFirstVisiblePosition() + 2000;
            int month = lv2.getFirstVisiblePosition() + 1;
            int day = lv3.getFirstVisiblePosition() + 1;
            String m = month < 10 ? "0" + String.valueOf(month) : String.valueOf(month);
            String d = day < 10 ? "0" + String.valueOf(day) : String.valueOf(day);
            return String.valueOf(year) + "-" + m + "-" + d;
        }

        private class MyAdapter extends BaseAdapter {
            private ArrayList list;

            public MyAdapter(ArrayList list) {
                this.list = list;
            }
            @Override
            public int getCount() {
                return list.size();
            }
            @Override
            public Object getItem(int position) {
                return null;
            }
            @Override
            public long getItemId(int position) {
                return position;
            }
            @Override
            public View getView(int position, View convertView, ViewGroup parent) {
                convertView = LayoutInflater.from(context).inflate(
                        R.layout.list_item, null);
                TextView tv = (TextView) convertView.findViewById(R.id.tv);
                tv.setText(list.get(position));
                return convertView;
            }
        }

    }


}

然后是activity的代码

package com.example.peiwc.myapplicationtime;

import android.app.Activity;
import android.app.Dialog;
import android.content.DialogInterface;

import android.os.Bundle;
import android.view.Display;
import android.view.Gravity;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends Activity {
    private Button btn;
    private TextView tv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv=(TextView)findViewById(R.id.textView);
        btn = (Button) findViewById(R.id.search_close_btn);
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                showDialog();
            }
        });
    }


    private void showDialog() {
        final CustomDialog.Builder builder = new CustomDialog.Builder(this);
        builder.setPositiveButton(new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int which) {
                tv.setText(builder.getStr());
                dialog.dismiss();
            }
        });

        builder.setNegativeButton(new android.content.DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int which) {
                dialog.dismiss();
            }
        });
        showDialog(builder);
    }

    private void showDialog(CustomDialog.Builder builder) {
        Dialog dialog = builder.create();
        Window dialogWindow = dialog.getWindow();
        WindowManager.LayoutParams lp = dialogWindow.getAttributes();
        dialogWindow.setGravity(Gravity.CENTER);
        WindowManager m = getWindowManager();
        Display d = m.getDefaultDisplay(); // 获取屏幕宽、高用
        WindowManager.LayoutParams p = dialogWindow.getAttributes(); // 获取对话框当前的参数值
        p.width = (int) (d.getWidth() * 0.75); // 宽度设置为屏幕的0.65
        dialogWindow.setAttributes(p);
        dialog.show();
    }
}

日期选择器就大功告成啦!


想下载完整demo,可以点击下方的链接哦!

http://download.youkuaiyun.com/detail/aa_chao/9622936

评论 7
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值