虽然android的源码也时不时的会去看,但大部分还是只能看懂部分。这里只把能完全看懂的源码上传了。
android.widget.AnalogClock
这个类比较简单,如果想要创建自己的View,可以从参考这个类开始。像TextView这种将近一万行的源码就太多了。还有一个比这个稍微难一点的是ImageView,也可以看那个类
public class AnalogClock extends View { private Time mCalendar; /** 时针背景 */ private Drawable mHourHand; /** 分针背景 */ private Drawable mMinuteHand; /** 表盘背景 */ private Drawable mDial; /** 表盘宽度 */ private int mDialWidth; /** 表盘高度 */ private int mDialHeight; /** 是否添加到WindowManager中 */ private boolean mAttached; private final Handler mHandler = new Handler(); private float mMinutes; private float mHour; /** 时间是否改变了 */ private boolean mChanged; public AnalogClock(Context context) { this(context, null); } public AnalogClock(Context context, AttributeSet attrs) { this(context, attrs, 0); } public AnalogClock(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); Resources r = mContext.getResources(); TypedArray a = context.obtainStyledAttributes( attrs, com.android.internal.R.styleable.AnalogClock, defStyle, 0); mDial = a.getDrawable(com.android.internal.R.styleable.AnalogClock_dial); if (mDial == null) { mDial = r.getDrawable(com.android.internal.R.drawable.clock_dial); } mHourHand = a.getDrawable(com.android.internal.R.styleable.AnalogClock_hand_hour); if (mHourHand == null) { mHourHand = r.getDrawable(com.android.internal.R.drawable.clock_hand_hour); } mMinuteHand = a.getDrawable(com.android.internal.R.styleable.AnalogClock_hand_minute); if (mMinuteHand == null) { mMinuteHand = r.getDrawable(com.android.internal.R.drawable.clock_hand_minute); } mCalendar = new Time(); mDialWidth = mDial.getIntrinsicWidth(); mDialHeight = mDial.getIntrinsicHeight(); } @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); if (!mAttached) { mAttached = true; IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_TIME_TICK); filter.addAction(Intent.ACTION_TIME_CHANGED); filter.addAction(Intent.ACTION_TIMEZONE_CHANGED); getContext().registerReceiver(mIntentReceiver, filter, null, mHandler); } // NOTE: It's safe to do these after registering the receiver since the receiver always runs // in the main thread, therefore the receiver can't run before this method returns. // The time zone may have changed while the receiver wasn't registered, so update the Time mCalendar = new Time(); // Make sure we update to the current time onTimeChanged(); } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); if (mAttached) { getContext().unregisterReceiver(mIntentReceiver); mAttached = false; } } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int widthMode = MeasureSpec.getMode(widthMeasureSpec); // layout提供的可用Width int widthSize = MeasureSpec.getSize(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); // layout提供的可用Height int heightSize = MeasureSpec.getSize(heightMeasureSpec); float hScale = 1.0f; float vScale = 1.0f; // 如果layout_width和layout_height是指定了值的 if (widthMode != MeasureSpec.UNSPECIFIED && widthSize < mDialWidth) { hScale = (float) widthSize / (float) mDialWidth; } if (heightMode != MeasureSpec.UNSPECIFIED && heightSize < mDialHeight) { vScale = (float )heightSize / (float) mDialHeight; } // 按照缩的比较小的缩放 float scale = Math.min(hScale, vScale); setMeasuredDimension(resolveSize((int) (mDialWidth * scale), widthMeasureSpec), resolveSize((int) (mDialHeight * scale), heightMeasureSpec)); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); mChanged = true; } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); boolean changed = mChanged; if (changed) { mChanged = false; } int availableWidth = mRight - mLeft; int availableHeight = mBottom - mTop; // 居中 int x = availableWidth / 2; int y = availableHeight / 2; final Drawable dial = mDial; int w = dial.getIntrinsicWidth(); int h = dial.getIntrinsicHeight(); boolean scaled = false; // 图片实际宽高比view的宽高大时,要对图片缩放 if (availableWidth < w || availableHeight < h) { scaled = true; float scale = Math.min((float) availableWidth / (float) w, (float) availableHeight / (float) h); canvas.save(); canvas.scale(scale, scale, x, y); } if (changed) { dial.setBounds(x - (w / 2), y - (h / 2), x + (w / 2), y + (h / 2)); } dial.draw(canvas); // 绘制时针 canvas.save(); canvas.rotate(mHour / 12.0f * 360.0f, x, y); final Drawable hourHand = mHourHand; if (changed) { w = hourHand.getIntrinsicWidth(); h = hourHand.getIntrinsicHeight(); hourHand.setBounds(x - (w / 2), y - (h / 2), x + (w / 2), y + (h / 2)); } hourHand.draw(canvas); canvas.restore(); // 绘制分针 canvas.save(); canvas.rotate(mMinutes / 60.0f * 360.0f, x, y); final Drawable minuteHand = mMinuteHand; if (changed) { w = minuteHand.getIntrinsicWidth(); h = minuteHand.getIntrinsicHeight(); minuteHand.setBounds(x - (w / 2), y - (h / 2), x + (w / 2), y + (h / 2)); } minuteHand.draw(canvas); canvas.restore(); // 结束 if (scaled) { canvas.restore(); } } private void onTimeChanged() { mCalendar.setToNow(); int hour = mCalendar.hour; int minute = mCalendar.minute; int second = mCalendar.second; mMinutes = minute + second / 60.0f; mHour = hour + mMinutes / 60.0f; mChanged = true; } private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (intent.getAction().equals(Intent.ACTION_TIMEZONE_CHANGED)) { String tz = intent.getStringExtra("time-zone"); mCalendar = new Time(TimeZone.getTimeZone(tz).getID()); } onTimeChanged(); invalidate(); } };}
不带布局的RadioGroup——NoLayoutRadioGroup
android提供的RadioGroup是一个LinearLayout,有时我们要在像TableLayout中的每个行使用一个RadioButton的话,RadioGroup就不太好用,所以参考RadioGroup实现了一个不带布局的RadioGroup.
/*** * 使用了这个类,RadioButton的OnCheckedChangeListener会被覆盖掉,所以 * 要使用监听器的话,使用这边的NonLayoutRadioGroup.OnCheckedChangeListener */public class NonLayoutRadioGroup { public interface OnCheckedChangeListener { /*** * @param group 触发该事件的NonLayoutRadioGroup * @param view 触发该事件的RadioButton, 当调用clearCheck时,view的值为null */ public void onCheckedChanged(NonLayoutRadioGroup group, RadioButton view); } private List<RadioButton> mRadioButtons = new ArrayList<RadioButton>(); private RadioButton mCheckButton; private OnCheckedChangeListener mListener; private CompoundButton.OnCheckedChangeListener mCheckedListener = new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { if (!isChecked) { mCheckButton = null; return; } if (mCheckButton != null) { mCheckButton.setChecked(false); } setCheckedButton((RadioButton) buttonView); } }; public void addRadioButton(RadioButton button) { // 不能添加null // 为没有id的RadioButton生成一个Id if (button.getId() == View.NO_ID) { button.setId(button.hashCode()); } button.setOnCheckedChangeListener(null); if (button.isChecked()) { // 移除原来的 if (mCheckButton != null) { mCheckButton.setChecked(false); } setCheckedButton(button); } button.setOnCheckedChangeListener(mCheckedListener); mRadioButtons.add(button); } public void removeRadioButton(RadioButton button) { // 添加到这里面的移除时,才需要清除其OnCheckedChangeListener if (mRadioButtons.contains(button)) { button.setOnCheckedChangeListener(null); mRadioButtons.remove(button); } } public void setOnCheckedChangeListener(OnCheckedChangeListener listener) { mListener = listener; } public void check(RadioButton button) { // check原来选中的 if (button != null && mCheckButton == button) { return; } // 移除选中的 if (mCheckButton != null) { mCheckButton.setChecked(false); } // 设置选中的 if (button != null) { button.setChecked(true); } // 触发监听器 setCheckedButton(button); } public void clearCheck() { check(null); } public RadioButton getCheckedRadioButton() { return mCheckButton; } // //////////////////////////////////////////////// /*** * 设置选中的RadioButton */ private void setCheckedButton(RadioButton button) { mCheckButton = button; if (mListener != null) { if (button != null) { mListener.onCheckedChanged(this, button); } else { mListener.onCheckedChanged(this, null); } } }}