chenglei1986/DatePicker源码解析(二)

接上一篇文章chenglei1986/DatePicker源码解析(一),我们继续将剩余的部分讲完,其实剩余的内容,就是利用Numberpicker来组成一个datePicker,代码非常的简单

为了实现自定义布局的效果,我们给Datepciker定制了一个layout,大家可以定制自己的layout

<?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="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" xmlns:app1="http://schemas.android.com/apk/res/com.example.androidtest">
<LinearLayout
    android:layout_width="fill_parent"
    android:layout_height="48dp"
    android:orientation="vertical"
    android:background="@color/base_color_gray_bg"
    android:gravity="center_vertical"
    >
    <TextView
        android:layout_width="wrap_content"
    	android:layout_height="wrap_content"
        android:textSize="18sp"
    	android:textColor="@color/base_color_text_black"
    	android:layout_marginLeft="10dp"
    	android:text="@string/bday"
        />
</LinearLayout>
<LinearLayout
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:padding="18dp"
    android:background="@color/base_color_text_white"
    android:orientation="horizontal" >
     <com.example.androidtest.NumberPicker
        android:id="@+id/day_picker"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:padding="16dp"
        app:flagText="asdasd"
        app:flagTextSize="30dp"
        app:flagTextColor="#abcdef"
        app:startNumber="1"
        app:endNumber="31"
        app:currentNumber="11"
        app:textColorNormal="#000000"
        app:textSizeHighLight="24dp"
        app:textColorHighLight="#abcdef"
        app:textSizeNormal="22dp"
        app:verticalSpacing="50dp"
        app:lines="3" />
	<LinearLayout
	    android:layout_width="0dp"
    	android:layout_height="fill_parent"
    	android:orientation="vertical"
    	android:layout_weight="0.7"
	    ></LinearLayout>
	<com.example.androidtest.NumberPicker
        android:id="@+id/month_picker"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:padding="16dp"
        app:startNumber="1"
        app:endNumber="12"
        app:currentNumber="16"
        app:textSizeHighLight="24dp"
        app:textSizeNormal="22dp"
        app:verticalSpacing="50dp"
        app:lines="3" />
    <LinearLayout
	    android:layout_width="0dp"
    	android:layout_height="fill_parent"
    	android:orientation="vertical"
    	android:layout_weight="0.7"
	    ></LinearLayout>
    <com.example.androidtest.NumberPicker
        android:id="@+id/year_picker"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:padding="16dp"
        app:startNumber="1970"
        app:endNumber="2050"
        app:currentNumber="2005"
        app:textSizeHighLight="24dp"
        app:textSizeNormal="22dp"
        app:verticalSpacing="50dp"
        app:lines="3" />
</LinearLayout>
<LinearLayout
    android:layout_width="fill_parent"
    android:layout_height="48dp"
    android:orientation="vertical"
    android:background="@color/base_color_header_green"
    >
    <Button
        android:id="@+id/finish"
        android:layout_width="fill_parent"
    	android:layout_height="48dp"
    	android:text="@string/finish"
    	android:background="@null"
    	android:textSize="18sp"
    	android:textColor="@color/base_color_text_white"
        />
</LinearLayout>
</LinearLayout>

在datepicker的初始化中,我们加载这个布局就可以了

public DatePicker(Context context, AttributeSet attrs) {
		super(context, attrs);
		mLayoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
		init();
	}

我们有三个numberpicker

public class DatePicker extends LinearLayout implements NumberPicker.OnValueChangeListener {
    //日期选择器    
    private NumberPicker mYearPicker;
    private NumberPicker mMonthPicker;
    private NumberPicker mDayOfMonthPicker;
    
    private Calendar mCalendar;
    //日期监听器
    private OnDateChangedListener mOnDateChangedListener;
    
    private LayoutInflater mLayoutInflater;

在init函数了,设置一些基本属性,监听等

private void init() {
		mLayoutInflater.inflate(R.layout.date_picker_layout, this, true);
		mYearPicker = (NumberPicker) findViewById(R.id.year_picker);
		mMonthPicker = (NumberPicker) findViewById(R.id.month_picker);
		mDayOfMonthPicker = (NumberPicker) findViewById(R.id.day_picker);
		//为每个numberpicker设置监听器(统一监听)
		mYearPicker.setOnValueChangeListener(this);
		mMonthPicker.setOnValueChangeListener(this);
		mDayOfMonthPicker.setOnValueChangeListener(this);

		//获取自定义选项数组
		if (!getResources().getConfiguration().locale.getCountry().equals("CN")
				&& !getResources().getConfiguration().locale.getCountry().equals("TW")) {

			String[] monthNames = getResources().getStringArray(R.array.month_name);
			mMonthPicker.setCustomTextArray(monthNames);

		}

		mCalendar = Calendar.getInstance();
		setDate(mCalendar.getTime());
	}

注意到日期格式不是一成不变的,例如2月,有可能是28,29天,我们利用Calendar类来为我们提供这个范围

/**
	 * 设置日期默认值
	 * @param date
	 */
	public void setDate(Date date) {
		mCalendar.setTime(date);
		mDayOfMonthPicker.setEndNumber(mCalendar.getActualMaximum(Calendar.DAY_OF_MONTH));

		mYearPicker.setCurrentNumber(mCalendar.get(Calendar.YEAR));
		mMonthPicker.setCurrentNumber(mCalendar.get(Calendar.MONTH) + 1);
		mDayOfMonthPicker.setCurrentNumber(mCalendar.get(Calendar.DAY_OF_MONTH));
	}

最后是监听器的设置,只要有一个numberpicker改变,就应该通知监听器

@Override
	/**
	 * 三个numberpicker,有一个改变,就产生通知
	 */
	public void onValueChange(final NumberPicker picker, final int oldVal, final int newVal) {

		if (picker == mYearPicker) {
			mCalendar.set(Calendar.YEAR, newVal);
			mDayOfMonthPicker.setEndNumber(mCalendar.getActualMaximum(Calendar.DAY_OF_MONTH));
		} else if (picker == mMonthPicker) {
			mCalendar.set(Calendar.MONTH, newVal - 1);
			mDayOfMonthPicker.setEndNumber(mCalendar.getActualMaximum(Calendar.DAY_OF_MONTH));
		} else if (picker == mDayOfMonthPicker) {
			mCalendar.set(Calendar.DAY_OF_WEEK, newVal);
		}

		notifyDateChanged();
	}
	

最后还有剩余的播放,我直接贴出Sound类

package com.example.androidtest;

import android.content.Context;
import android.media.AudioManager;
import android.media.SoundPool;

public class Sound {

	private SoundPool mSoundPool;
	private AudioManager mAudioManager;
	private float mCurrVolume;
	private Context mContext;
	private int mSoundId;

	public Sound(Context context) {
		mContext = context;
		mSoundPool = new SoundPool(1, AudioManager.STREAM_SYSTEM, 0);
		mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
	}

	/**
	 * 播放声音
	 */
	public void playSoundEffect() {
		mCurrVolume = mAudioManager.getStreamVolume(AudioManager.STREAM_SYSTEM);
		if (mSoundId != 0) {
			mSoundPool.play(mSoundId, mCurrVolume, mCurrVolume, 0, 0, 1);
		} else {
			mAudioManager.playSoundEffect(AudioManager.FX_KEY_CLICK, mCurrVolume);
		}
	}

	/**
	 * 设置声音
	 * @param resId
	 */
	public void setCustomSound(int resId) {
		mSoundId = mSoundPool.load(mContext, resId, 1);
	}

}

这个类会产生系统的默认声音,我们使用声音之前,要为datepicker设置

 public void setSoundEffect(Sound sound) {
    	mYearPicker.setSoundEffect(sound);
    	mMonthPicker.setSoundEffect(sound);
    	mDayOfMonthPicker.setSoundEffect(sound);
    }

    @Override
    public void setSoundEffectsEnabled(boolean soundEffectsEnabled) {
    	super.setSoundEffectsEnabled(soundEffectsEnabled);
    	mYearPicker.setSoundEffectsEnabled(soundEffectsEnabled);
    	mMonthPicker.setSoundEffectsEnabled(soundEffectsEnabled);
    	mDayOfMonthPicker.setSoundEffectsEnabled(soundEffectsEnabled);
    }

以上的代码都非常简单,更重要的Numberpicker的理解,搭建好numberpicker,datepciker自然就出来了

最后贴出datepicker完整代码

package com.example.androidtest;

import java.util.Calendar;
import java.util.Date;

import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.widget.LinearLayout;

public class DatePicker extends LinearLayout implements NumberPicker.OnValueChangeListener {
	//日期选择器
	private NumberPicker mYearPicker;
	private NumberPicker mMonthPicker;
	private NumberPicker mDayOfMonthPicker;

	private Calendar mCalendar;
	//日期监听器
	private OnDateChangedListener mOnDateChangedListener;

	private LayoutInflater mLayoutInflater;

	public DatePicker(Context context) {
		this(context, null);
	}

	public DatePicker(Context context, AttributeSet attrs) {
		super(context, attrs);
		mLayoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
		init();
	}

	private void init() {
		mLayoutInflater.inflate(R.layout.date_picker_layout, this, true);
		mYearPicker = (NumberPicker) findViewById(R.id.year_picker);
		mMonthPicker = (NumberPicker) findViewById(R.id.month_picker);
		mDayOfMonthPicker = (NumberPicker) findViewById(R.id.day_picker);
		//为每个numberpicker设置监听器(统一监听)
		mYearPicker.setOnValueChangeListener(this);
		mMonthPicker.setOnValueChangeListener(this);
		mDayOfMonthPicker.setOnValueChangeListener(this);

		//获取自定义选项数组
		if (!getResources().getConfiguration().locale.getCountry().equals("CN")
				&& !getResources().getConfiguration().locale.getCountry().equals("TW")) {

			String[] monthNames = getResources().getStringArray(R.array.month_name);
			mMonthPicker.setCustomTextArray(monthNames);

		}

		mCalendar = Calendar.getInstance();
		setDate(mCalendar.getTime());
	}

	/**
	 * 设置日期默认值
	 * @param date
	 */
	public void setDate(Date date) {
		mCalendar.setTime(date);
		mDayOfMonthPicker.setEndNumber(mCalendar.getActualMaximum(Calendar.DAY_OF_MONTH));

		mYearPicker.setCurrentNumber(mCalendar.get(Calendar.YEAR));
		mMonthPicker.setCurrentNumber(mCalendar.get(Calendar.MONTH) + 1);
		mDayOfMonthPicker.setCurrentNumber(mCalendar.get(Calendar.DAY_OF_MONTH));
	}

	@Override
	/**
	 * 三个numberpicker,有一个改变,就产生通知
	 */
	public void onValueChange(final NumberPicker picker, final int oldVal, final int newVal) {

		if (picker == mYearPicker) {
			mCalendar.set(Calendar.YEAR, newVal);
			mDayOfMonthPicker.setEndNumber(mCalendar.getActualMaximum(Calendar.DAY_OF_MONTH));
		} else if (picker == mMonthPicker) {
			mCalendar.set(Calendar.MONTH, newVal - 1);
			mDayOfMonthPicker.setEndNumber(mCalendar.getActualMaximum(Calendar.DAY_OF_MONTH));
		} else if (picker == mDayOfMonthPicker) {
			mCalendar.set(Calendar.DAY_OF_WEEK, newVal);
		}

		notifyDateChanged();
	}

	/**
     * The callback used to indicate the user changes\d the date.
     */
    public interface OnDateChangedListener {

        /**
         * Called upon a date change.
         *
         * @param view The view associated with this listener.
         * @param year The year that was set.
         * @param monthOfYear The month that was set (0-11) for compatibility
         *            with {@link java.util.Calendar}.
         * @param dayOfMonth The day of the month that was set.
         */
        void onDateChanged(DatePicker view, int year, int monthOfYear, int dayOfMonth);
    }

    public void setOnDateChangedListener(OnDateChangedListener l) {
    	mOnDateChangedListener = l;
    }

    private void notifyDateChanged() {
    	if (mOnDateChangedListener != null) {
    		mOnDateChangedListener.onDateChanged(this, getYear(), getMonth(), getDayOfMonth());
    	}
    }

    public int getYear() {
    	return mCalendar.get(Calendar.YEAR);
    }

    public int getMonth() {
    	return mCalendar.get(Calendar.MONTH) + 1;
    }

    public int getDayOfMonth() {
    	return mCalendar.get(Calendar.DAY_OF_MONTH);
    }

    public void setSoundEffect(Sound sound) {
    	mYearPicker.setSoundEffect(sound);
    	mMonthPicker.setSoundEffect(sound);
    	mDayOfMonthPicker.setSoundEffect(sound);
    }

    @Override
    public void setSoundEffectsEnabled(boolean soundEffectsEnabled) {
    	super.setSoundEffectsEnabled(soundEffectsEnabled);
    	mYearPicker.setSoundEffectsEnabled(soundEffectsEnabled);
    	mMonthPicker.setSoundEffectsEnabled(soundEffectsEnabled);
    	mDayOfMonthPicker.setSoundEffectsEnabled(soundEffectsEnabled);
    }

}
时间: 2024-11-07 21:35:13

chenglei1986/DatePicker源码解析(二)的相关文章

chenglei1986/DatePicker源码解析(一)

DatePicker在android其实是有提供的一个控件,相信有不少的人使用过它,但是这个控件的外观我们只能做一些简单的设定(原生的),如果我们有更高需求,希望能自定义我们的datepicker的外观,希望赋予它更多的功能,我们就需要自定义一个datepciker控件. 在github上,我发现了一个chenglei1986/DatePicker的项目,可以实现上面的需求.地址是https://github.com/chenglei1986/DatePicker 这个自定义控件非常灵活,通过学

Spring 源码解析之HandlerAdapter源码解析(二)

Spring 源码解析之HandlerAdapter源码解析(二) 前言 看这篇之前需要有Spring 源码解析之HandlerMapping源码解析(一)这篇的基础,这篇主要是把请求流程中的调用controller流程单独拿出来了 解决上篇文章遗留的问题 getHandler(processedRequest) 这个方法是如何查找到对应处理的HandlerExecutionChain和HandlerMapping的,比如说静态资源的处理和请求的处理肯定是不同的HandlerMapping ge

开源日历控件DatePicker源码解析

在一些项目开发中,会使用日历去标识事务,所以根据美工出的效果图,我们可以采用不同的方法去实现.比如通过GridView扣扣你敢.自定义View实现日历控件,这些都是我们解决问题的手段,我也实现过一个自定义日历控件(Android自定义控件之日历控件55993)),由于我只是粗糙的进行实现,并没有进行过多的在控件的可扩展性上进行打磨设计,所以在本篇文章中,我秉着学习的态度分析下爱哥的鼎力巨作DatePicker-DatePicker. DatePicker开源项目地址:[https://githu

erlang下lists模块sort(排序)方法源码解析(二)

上接erlang下lists模块sort(排序)方法源码解析(一),到目前为止,list列表已经被分割成N个列表,而且每个列表的元素是有序的(从大到小) 下面我们重点来看看mergel和rmergel模块,因为我们先前主要分析的split_1_*对应的是rmergel,我们先从rmergel查看,如下 ....................................................... split_1(X, Y, [], R, Rs) -> rmergel([[Y, X

AFNetworking2.0源码解析&lt;二&gt;

本篇我们继续来看看AFNetworking的下一个模块 — AFURLRequestSerialization. AFURLRequestSerialization用于帮助构建NSURLRequest,主要做了两个事情: 1.构建普通请求:格式化请求参数,生成HTTP Header. 2.构建multipart请求. 分别看看它在这两点具体做了什么,怎么做的. 1.构建普通请求 A.格式化请求参数 一般我们请求都会按key=value的方式带上各种参数,GET方法参数直接加在URL上,POST方

volley源码解析(二)--Request&lt;T&gt;类的介绍

在上一篇文章中,我们已经提到volley的使用方式和设计的整体思路,从这篇文章开始,我就要结合具体的源码来给大家说明volley功能的具体实现. 我们第一个要介绍的类是Request<T>这个一个抽象类,我将Request称为一个请求,通过继承Request<T>来自定义request,为volley提供了更加灵活的接口. Request<T>中的泛型T,是指解析response以后的结果.在上一篇文章中我们知道,ResponseDelivery会把response分派

Mybatis 源码解析(二) - Configuration.xml解析

文章个人学习源码所得,若存在不足或者错误之处,请大家指出. 上一章中叙述了Configuration.xml流化到Mybatis内存中的过程,那么接下来肯定就是Configuration.xml文件解析操作,在Mybatis中,这个解析的操作由SqlSesssionFactoryBuilder负责.接下来我们看看SqlSessionFactoryBuilder的方法签名: SqlSessionFactoryBuilder提供了9个签名方法,其中前8个方法都是Configuration.xml的解

jQuery 源码解析(二十五) DOM操作模块 html和text方法的区别

html和text都可以获取和修改DOM节点里的内容,方法如下: html(value)     ;获取匹配元素集合中的一个元素的innerHTML内容,或者设置每个元素的innerHTML内容,                ;value可选,可以是html代码或返回html代码的函数,如果没有参数则获取匹配元素集合中第一个元素的innerHTML内容 text(text)         ;获取匹配元素集合中所有元素合并后的文本内容,或者设置每个元素的文本内容,封装了createTextNo

第37篇 Asp.Net源码解析(二)--详解HttpApplication

这篇文章花了点时间,差点成烂到电脑里面,写的过程中有好几次修改,最终的这个版本也不是很满意,东西说的不够细,还需要认真的去看下源码才能有所体会,先这样吧,后面有时间把细节慢慢的再修改.顺便对于开发的学习,个人是觉得源码的阅读是最快的提高方式,当然阅读不是走马观花,应该多次阅读. 上次说到获得HttpApplication对象的创建,创建完成后调用InitInternal方法,这个方法任务比较多,也比较长,这里就不贴全码了,一个一个过程的去说: 初始化HttpModule 对于HttpModule