美文网首页Android程序员Android进阶之路
Android三级联动wheel代码分析(一)

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

作者: 许晓北 | 来源:发表于2015-12-16 18:27 被阅读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的构造方面代码结束。后续已经写好,可以点我个人信息查看。


    相关文章

      网友评论

      • _Ryeeeeee:如果调整一下代码的排版就更好了
        许晓北:@_Ryeeeeee :grin: 恩恩。刚用这个不太熟悉。。
      • 曾樑::+1::+1:
        许晓北:@曾樑 写的有点乱。。。 :sweat: 希望能共同探讨~

      本文标题:Android三级联动wheel代码分析(一)

      本文链接:https://www.haomeiwen.com/subject/cytphttx.html