Android程序员Android进阶之路

Android三级联动wheel代码分析(一)

2015-12-16  本文已影响848人  许晓北

联系不到源代码作者  源码地址  ,闲下来分析一下wheel的原理帮助自己更明白点吧。。当然github上面也有很多很好的wheel项目。

如图的效果想要首先肯定要自定义View。

另外这个里面的城市信息是放在assets下面的名称area.json里。我们先从整个这个控件的代码看起把。

唔,写到哪算哪吧。首先选择器肯定需要自定义view

public class ScrollerNumberPicker extends View{

public ScrollerNumberPicker(Context context, AttributeSet attrs,int defStyle){

super(context, attrs, defStyle);
init(context, attrs);
initData();
 }
public ScrollerNumberPicker(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
initData();
 }
public ScrollerNumberPicker(Context context) {
super(context);
initData();
}
private void init(Context context, AttributeSet attrs) {

TypedArray attribute = context.obtainStyledAttributes(attrs,R.styleable.NumberPicker);

/** 单元格高度 */

unitHeight = (int) attribute.getDimension(R.styleable.NumberPicker_unitHight, 32);

/** 默认字体 */

normalFont = attribute.getDimension(R.styleable.NumberPicker_normalTextSize, 14.0f);

/** 选中的时候字体 */

selectedFont = attribute.getDimension(R.styleable.NumberPicker_selecredTextSize, 22.0f);

/** 显示多少个内容 */

itemNumber = attribute.getInt(R.styleable.NumberPicker_itemNumber, 7);

/** 默认字体颜色 */

normalColor = attribute.getColor(R.styleable.NumberPicker_normalTextColor, 0xff000000);

/** 选中时候的字体颜色 */

selectedColor = attribute.getColor(R.styleable.NumberPicker_selecredTextColor, 0xffff0000);

/** 线的默认颜色 */

lineColor = attribute.getColor(R.styleable.NumberPicker_lineColor,0xff000000);

/** 蒙板高度 */

maskHight = attribute.getDimension(R.styleable.NumberPicker_maskHight, 48.0f);

/** 是否允许选空 */

noEmpty = attribute.getBoolean(R.styleable.NumberPicker_noEmpty,false);

/** 是否可用 */

isEnable = attribute.getBoolean(R.styleable.NumberPicker_isEnable,true);

//调用recycle()方法,否则这次的设定会对下次的使用造成影响

attribute.recycle();

/** 控件高度 */

controlHeight = itemNumber * unitHeight;

}
}

关于TypedArray的知识简单说下

在自定义view的代码中引入自定义属性,修改构造函数

context通过调用obtainStyledAttributes方法来获取一个TypeArray,然后由该TypeArray来对属性进行设置

obtainStyledAttributes方法有三个,我们最常用的是有一个参数的obtainStyledAttributes(int[] attrs),其参数直接styleable中获得

TypedArray a = context.obtainStyledAttributes(attrs,R.styleable.MyView);

调用结束后务必调用recycle()方法,否则这次的设定会对下次的使用造成影响

/**

* 初始化数据

*/

private void initData() {

/** 正在修改数据,避免ConcurrentModificationException异常 */

isClearing = true;

/** 选择的内容 */

itemList.clear();

/** 设置数据 */ datalist

for (int i = 0; i < dataList.size(); i++) {

ItemObject itmItemObject = new ItemObject();

itmItemObject.id = i;

itmItemObject.itemText = dataList.get(i);

itmItemObject.x = 0;

itmItemObject.y = i * unitHeight;

itemList.add(itmItemObject);

}

isClearing = false;

}

关于ConcurrentModificationException异常

对Vector、ArrayList在迭代的时候如果同时对其进行修改就会抛出java.util.ConcurrentModificationException异常

关键点就在于:调用list.remove()方法导致modCount和expectedModCount的值不一致。

注意,像使用for-each进行迭代实际上也会出现这种问题。

expectedModCount:表示对ArrayList修改次数的期望值,它的初始值为modCount。

每次调用add()方法或者remove()方法就会对modCount进行加1操作

/**

* 单条内容

*

* @author zoudong

*/

private class ItemObject {

/** id */

public int id = 0;

/** 内容 */

public String itemText = "";

/** x坐标 */

public int x = 0;

/** y坐标 */

public int y = 0;

/** 移动距离 */

public int move = 0;

/** 字体画笔 */

private Paint textPaint;

/** 字体范围矩形 */

private Rect textRect;

public ItemObject() {

super();

}

/**

* 绘制自身

*

* @param canvas

*/

public void drawSelf(Canvas canvas) {

if (textPaint == null) {

textPaint = new Paint();

textPaint.setAntiAlias(true);

}

if (textRect == null)

textRect = new Rect();

// 判断是否被选择,见下面代码分析

if (isSelected()) {

textPaint.setColor(selectedColor);

// 获取距离标准位置的距离

float moveToSelect = moveToSelected();

moveToSelect = moveToSelect > 0 ? moveToSelect : moveToSelect

* (-1);

// 计算当前字体大小

float textSize = (float) normalFont

+ ((float) (selectedFont - normalFont) * (1.0f - (float) moveToSelect

/ (float) unitHeight));

textPaint.setTextSize(textSize);

} else {

textPaint.setColor(normalColor);

textPaint.setTextSize(normalFont);

}

// 返回包围整个字符串的最小的一个Rect区域

textPaint.getTextBounds(itemText, 0, itemText.length(), textRect);

// 判断是否可视

if (!isInView())

return;

// 绘制内容

canvas.drawText(itemText, x + controlWidth / 2 - textRect.width()

/ 2, y + move + unitHeight / 2 + textRect.height() / 2,

textPaint);

}

/**

* 是否在可视界面内

*

* @param rect

* @return

*/

public boolean isInView() {

if (y + move > controlHeight

|| (y + move + unitHeight / 2 + textRect.height() / 2) < 0)

return false;

return true;

}

/**

* 移动距离

*

* @param _move

*/

public void move(int _move) {

this.move = _move;

}

/**

* 设置新的坐标

*

* @param move

*/

public void newY(int _move) {

this.move = 0;

this.y = y + _move;

}

/**

* 判断是否在选择区域内

*画出来矩形以左上为(0,0)点。下为Y轴,然后进行判断

* @return

*/

public boolean isSelected() {

//手指移动中间部分判断

if ((y + move) >= controlHeight / 2 - unitHeight / 2 + 2

&& (y + move) <= controlHeight / 2 + unitHeight / 2 - 2)

return true;

//手指移动最上部分判断

if ((y + move + unitHeight) >= controlHeight / 2 - unitHeight / 2

+ 2

&& (y + move + unitHeight) <= controlHeight / 2

+ unitHeight / 2 - 2)

return true;

//手指移动最下部分判断

if ((y + move) <= controlHeight / 2 - unitHeight / 2 + 2

&& (y + move + unitHeight) >= controlHeight / 2

+ unitHeight / 2 - 2)

return true;

return false;

}

/**

* 获取移动到标准位置需要的距离

*/

public float moveToSelected() {

return (controlHeight / 2 - unitHeight / 2) - (y + move);

}

}

第一部分代码就分析到这边,明天接着分析Android三级联动wheel代码分析(二)~第一部分自定义view的构造方面代码结束。后续已经写好,可以点我个人信息查看。


上一篇下一篇

猜你喜欢

热点阅读