前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >看得见的数据结构Android版之表的数组实现(视图篇)

看得见的数据结构Android版之表的数组实现(视图篇)

作者头像
张风捷特烈
发布2018-12-17 10:54:48
6690
发布2018-12-17 10:54:48
举报
先留图镇楼:

表结构的常规操作

表结构的常规操作.gif

数组的扩容与缩容

数组的扩容与缩容


一、先绘制操作界面:
1.自定义View:ArrayView

准备一个主画笔和主路径并确定一些常量 然后用analyze包绘制封装好的网格和坐标系以便查看

代码语言:javascript
复制
/**
 * 作者:张风捷特烈<br/>
 * 时间:2018/11/21 0021:8:01<br/>
 * 邮箱:1981462002@qq.com<br/>
 * 说明:数组实现表结构---测试视图
 */
public class ArrayView<E> extends View {
    private Point mCoo = new Point(200, 150);//坐标系
    private Picture mCooPicture;//坐标系canvas元件
    private Picture mGridPicture;//网格canvas元件

    private Path mPath;//主路径
    private Paint mPaint;//主画笔

    private static final int OFFSET_X = 10;//X空隙
    private static final int OFFSET_Y = 60;//Y空隙
    private static final int OFFSET_OF_TXT_Y = 10;//文字的偏移
    private static final int BOX_RADIUS = 10;//数组盒子的圆角

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

    public ArrayView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();//初始化
    }

    private void init() {
        //初始化主画笔
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setColor(Color.BLUE);
        mPaint.setStrokeWidth(5);
        mPaint.setTextAlign(Paint.Align.CENTER);
        mPaint.setTextSize(50);
        //初始化主路径
        mPath = new Path();
        //辅助线
         mCooPicture = HelpDraw.getCoo(getContext(), mCoo,false);//坐标系:无文字
        mGridPicture = HelpDraw.getGrid(getContext());//网格
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        HelpDraw.draw(canvas, mGridPicture);
        canvas.save();
        canvas.translate(mCoo.x, mCoo.y);//画布移到坐标原点
        //TODO draw
        canvas.restore();
        HelpDraw.draw(canvas, mCooPicture);
    }
}

坐标系.png


2.把后面要用的画笔准备一下:
代码语言:javascript
复制
private void init() {
    //初始化主画笔
    mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    mPaint.setColor(Color.BLUE);
    mPaint.setStrokeWidth(5);
    mPaint.setTextAlign(Paint.Align.CENTER);
    mPaint.setTextSize(50);
    //初始化主路径
    mPath = new Path();
    //初始化文字画笔
    mTxtPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    mTxtPaint.setColor(Color.WHITE);
    mTxtPaint.setTextAlign(Paint.Align.CENTER);
    mTxtPaint.setTextSize(40);
    //初始化路径画笔
    mPathPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    mPathPaint.setColor(Color.GRAY);
    mPathPaint.setStyle(Paint.Style.STROKE);
    mCooPicture = HelpDraw.getCoo(getContext(), mCoo,false);
    mGridPicture = HelpDraw.getGrid(getContext());
    //初始化圆球按钮画笔
    mCtrlPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    mCtrlPaint.setColor(Color.RED);
    mCtrlPaint.setTextAlign(Paint.Align.CENTER);
    mCtrlPaint.setTextSize(30);
}
3.准备小球的信息

你也可以将这些信息封装成一个bean,这里为了bean太多容易混淆,用几个数组记录信息

代码语言:javascript
复制
    private static final Point[] CTRL_POS = new Point[]{//控制按钮的点位
            new Point(-100, 100),//添加
            new Point(-100, 300),//更新
            new Point(-100, 500),//查看
            new Point(-100, 700),//删除

            new Point(700, -70),//定点添加
            new Point(700 + 300, -70),//定值查询
            new Point(700 + 300 * 2, -70),//定点删除
            new Point(700 + 300 * 3, -70),//清除

    };

    private static int[] CTRL_COLOR = new int[]{//控制按钮的颜色
            0xff1EF519,//添加
            0xff2992F2,//更新
            0xffB946F4,//添加
            0xffF50C0C,//删除

            0xff1EF519,//定点添加
            0xffB946F4,//定值查询
            0xffF50C0C,//定点删除
            0xffF46410,//清除
    };

    private static final String[] CTRL_TXT = new String[]{//控制按钮的文字
            "添加",//添加
            "更新",//更新
            "查寻",//添加
            "删除",//删除

            "定点+",//定点添加
            "值查",//定值查询
            "定点-",//定点删除
            "清空",//清除按键
    };

    private static final int CTRL_RADIUS = 50;//控制按钮的半径

3.绘制小圆球:

人狠话不多----一个循环,一波带走

代码语言:javascript
复制
/**
 * 控制面板--圆球
 *
 * @param canvas 画布
 */
private void ctrlView(Canvas canvas) {
    for (int i = 0; i < CTRL_POS.length; i++) {
        mCtrlPaint.setColor(CTRL_COLOR[i]);
        canvas.drawCircle(CTRL_POS[i].x, CTRL_POS[i].y, CTRL_RADIUS, mCtrlPaint);
        canvas.drawText(CTRL_TXT[i], CTRL_POS[i].x, CTRL_POS[i].y + OFFSET_OF_TXT_Y, mTxtPaint);
    }
}

绘制控制按钮.png

这就...画完了?对...这就画完了


三、小球的点击事件(区域判断)
1.有请吾王麾下十二战神之一:审断之神(JudgeMan.java)
代码语言:javascript
复制
/**
 * 审断之神能力一:第一形态:区域限定----判断出是否在某点的半径为r圆范围内
 *
 * @param srcX 目标点X
 * @param srcY 目标点Y
 * @param dstX 主动点X
 * @param dstY 主动点Y
 * @param r    半径区域
 * @return 是否在区域内
 */
public static boolean judgeCircleArea(float srcX, float srcY, float dstX, float dstY, float r) {
    return disPos2d(srcX, srcY, dstX, dstY) <= r;
}

/**
 * 审断之神被动能力一:两点间距离函数
 * @param srcX 目标点X
 * @param srcY 目标点Y
 * @param dstX 主动点X
 * @param dstY 主动点Y
 * @return 两点间距离函数
 */
private static float disPos2d(float srcX, float srcY, float dstX, float dstY) {
    return (float) Math.sqrt((srcX - dstX) * (srcX - dstX) + (srcY - dstY) * (srcY - dstY));
}

判断dst点是否在src周围r的圆内.png


2.先写一下回调监听接口:OnCtrlClickListener

兵马未动,粮草先行,有接口好办事

代码语言:javascript
复制
/**
 * 作者:张风捷特烈<br/>
 * 时间:2018/11/21 0021:10:17<br/>
 * 邮箱:1981462002@qq.com<br/>
 * 说明:控操作接口
 */
public interface OnCtrlClickListener<T> {
    /**
     * 添加时回调
     * @param view
     */
    void onAdd(T view);
    /**
     * 定点添加时回调
     * @param view
     */
    void onAddByIndex(T view);
    /**
     * 移除时回调
     * @param view
     */
    void onRemove(T view);
    /**
     * 定点移除时回调
     * @param view
     */
    void onRemoveByIndex(T view);
    /**
     * 设置时回调
     * @param view
     */
    void onSet(T view);
    /**
     * 查询时回调
     * @param view
     */
    void onFind(T view);
    /**
     * 定值查询时回调
     * @param view
     */
    void onFindByData(T view);
    /**
     * 清空时回调
     * @param view
     */
    void onClear(T view);
}
3.触摸事件获取主动点:

还是一个for循环一波带走----(mark:一开始我也是一个一个if,然后发现可以优化,才变得优雅的) 也许无法一步想到位,但可以先实现,然后再优化,我就喜欢这种一波带走的感觉 注意点:downX和downY要相对于canvas的坐标系,所以要偏移一下

代码语言:javascript
复制
private OnCtrlClickListener<ArrayView<E>> mOnCtrlClickListener;//监听器
public void setOnCtrlClickListener(OnCtrlClickListener<ArrayView<E>> onCtrlClickListener) {
    mOnCtrlClickListener = onCtrlClickListener;
}

@Override
public boolean onTouchEvent(MotionEvent event) {
    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            float downX = event.getX() - mCoo.x;
            float downY = event.getY() - mCoo.y;
            for (int i = 0; i < CTRL_POS.length; i++) {
                if (JudgeMan.judgeCircleArea( //区域判定
                        CTRL_POS[i].x, CTRL_POS[i].y,
                        downX, downY, CTRL_RADIUS * 1.2f)) {
                    if (mOnCtrlClickListener != null) {
                        switch (i) {
                            case 0://插入尾部
                                mOnCtrlClickListener.onAdd(this);
                                break;
                            case 1://更新
                                mOnCtrlClickListener.onSet(this);
                                  contactTest();
                                break;
                            case 2://查找
                                mOnCtrlClickListener.onFind(this);
                                break;
                            case 3://删除尾部
                                selectIndex = mArrayBoxes.size() - 1;
                                mAnimator.start();
                                break;
                            case 4://定点添加尾部
                                mOnCtrlClickListener.onAddByIndex(this);
                                break;
                            case 5://定值查询
                                mOnCtrlClickListener.onFindByData(this);
                                break;
                            case 6://定点移除
                                mAnimator.start();
                                break;
                            case 7://清空
                                mOnCtrlClickListener.onClear(this);
                                break;
                        }
                        CTRL_COLOR[i] = 0xff54E1F8;//点击更换颜色
                    }
                }
            }
            updayeSelectIndex(downX, downY);//更新selectIndex
            break;
        case MotionEvent.ACTION_UP://还原颜色
            CTRL_COLOR[0] = 0xff1EF519;
            CTRL_COLOR[1] = 0xff2992F2;
            CTRL_COLOR[2] = 0xffB946F4;
            CTRL_COLOR[3] = 0xffF50C0C;
            CTRL_COLOR[4] = 0xff1EF519;
            CTRL_COLOR[5] = 0xffB946F4;
            CTRL_COLOR[6] = 0xffF50C0C;
            CTRL_COLOR[7] = 0xffF46410;
            break;
    }
    invalidate();//记得重绘
    return true;
}
4.Activity使用接口:
代码语言:javascript
复制
public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ArrayView<String> view = new ArrayView<>(this);
        view.setOnCtrlClickListener(new OnCtrlClickListener<ArrayView<String>>() {
            @Override
            public void onAdd(ArrayView<String> view) {
                Toast.makeText(MainActivity.this, "onAdd", Toast.LENGTH_SHORT).show();
            }
            @Override
            public void onAddByIndex(ArrayView<String> view) {
                Toast.makeText(MainActivity.this, "onAddByIndex", Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onRemove(ArrayView<String> view) {
                Toast.makeText(MainActivity.this, "onRemove", Toast.LENGTH_SHORT).show();
            }
            @Override
            public void onRemoveByIndex(ArrayView<String> view) {
                Toast.makeText(MainActivity.this, "onRemoveByIndex", Toast.LENGTH_SHORT).show();
            }
            @Override
            public void onSet(ArrayView<String> view) {
                Toast.makeText(MainActivity.this, "onSet", Toast.LENGTH_SHORT).show();
            }
            @Override
            public void onFind(ArrayView<String> view) {
                Toast.makeText(MainActivity.this, "onFind", Toast.LENGTH_SHORT).show();
            }
            @Override
            public void onFindByData(ArrayView<String> view) {
                Toast.makeText(MainActivity.this, "onFindByData", Toast.LENGTH_SHORT).show();
            }
            @Override
            public void onClear(ArrayView<String> view) {
                Toast.makeText(MainActivity.this, "onFindByData", Toast.LENGTH_SHORT).show();
            }
        });
        setContentView(view);
    }
}

OK,完美运行,核心在审断之神的judgeCircleArea

查看按钮运行状况.gif


三、正文来了,绘制数据结构:
1.可绘制对象单体:使用数据结构单体的父类

拥有坐标、颜色、速度三种核心属性

代码语言:javascript
复制
/**
 * 作者:张风捷特烈<br/>
 * 时间:2018/11/21 0021:8:50<br/>
 * 邮箱:1981462002@qq.com<br/>
 * 说明:可显示出来的基本条件
 */
public class Viewable {
    public float x;//单体的x坐标
    public float y;//单体的y坐标
    public int color = 0xff43A3FA;//单体的颜色

    public float vX;//单体的水平速度
    public float vY;//单体的数值速度

    public Viewable() {
    }

    public Viewable(float x, float y) {
        this.x = x;
        this.y = y;
    }
}
2.数组表结构单体的绘图承载对象:

数组盒子:拥有索引和数据两个额外属性

代码语言:javascript
复制
/**
 * 作者:张风捷特烈<br/>
 * 时间:2018/11/21 0021:8:46<br/>
 * 邮箱:1981462002@qq.com<br/>
 * 说明:模型层数组的单体
 */
public class ArrayBox<T> extends Viewable {

    public int index;//数组单体索引
    public T data;//数据结构承载的核心数据

    @Override
    public boolean equals(Object obj) {
        return ((ArrayBox) obj).data == data;
    }

    public ArrayBox(T data) {
        this.data = data;
    }

    public ArrayBox(float x, float y) {
        super(x, y);
    }
}
3.绘制数组的长度个空白矩形
1)如何根据索引确定点位

就是稍微画个图,看看有什么关系,找到通式就ok了(代码巧多了,写字就是丑...) 然后我们用上篇的数组表结构来进行测试

位置计算.jpg

2)绘制数组的长度个空白矩形

根据上面的分析图,确定了第x列,第y行的矩形坐标,应该就不难画了 注意:绘制数组的长度个空白矩形,数组的长度!! 数组的长度个!!,不是集合大小

本来应该把数组完全封装在数组表结构中的,这里为了演示扩容和缩容,数组长度还是必要的

代码语言:javascript
复制
//创建一个上篇定义的数组表类,泛型当然是要画的数组盒子了
private IChart<ArrayBox<E>> mArrayBoxes = new ArrayChart<>();

/**
 * 绘制数组的长度个空白矩形
 *
 * @param canvas
 */
private void helpView(Canvas canvas) {
    for (int i = 0; i < mArrayBoxes.capacity(); i++) {
        int y = i / 8;//行坐标
        int x = i % 8;//列坐标
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setColor(0xff821AFA);
        canvas.drawRoundRect(
                (Cons.BOX_WIDTH + OFFSET_X) * x, (Cons.BOX_HEIGHT + OFFSET_Y) * y,
                (Cons.BOX_WIDTH + OFFSET_X) * x + Cons.BOX_WIDTH, 
                (Cons.BOX_HEIGHT + OFFSET_Y) * y + Cons.BOX_HEIGHT,
                BOX_RADIUS, BOX_RADIUS, mPaint);
        mTxtPaint.setColor(0xff821AFA);
        canvas.drawText(i + "",
                (Cons.BOX_WIDTH + OFFSET_X) * x + Cons.BOX_WIDTH / 2,
                (Cons.BOX_HEIGHT + OFFSET_Y) * y + 3 * OFFSET_OF_TXT_Y, mTxtPaint);
    }

}

数组初始长度为10,没错

数组体现.png


4.绘制表结构

根据mArrayBoxes的大小,绘制出mArrayBoxes里面的所有元素。 绘制单体在前言篇已经给出,这里只是加上了偏移量,应该不难理解。

代码语言:javascript
复制
/**
 * 绘制表结构
 * @param canvas
 */
private void dataView(Canvas canvas) {
    mPaint.setColor(Color.BLUE);
    mPaint.setStyle(Paint.Style.FILL);
    mPath.reset();
    for (int i = 0; i < mArrayBoxes.size(); i++) {
        ArrayBox box = mArrayBoxes.get(i);
        mPaint.setColor(box.color);
        canvas.drawRoundRect(
                box.x, box.y, box.x + Cons.BOX_WIDTH, box.y + Cons.BOX_HEIGHT,
                BOX_RADIUS, BOX_RADIUS, mPaint);
        mPath.moveTo(box.x, box.y);
        mPath.rCubicTo(Cons.BOX_WIDTH / 2, Cons.BOX_HEIGHT / 2,
                Cons.BOX_WIDTH / 2, Cons.BOX_HEIGHT / 2, Cons.BOX_WIDTH, 0);
        canvas.drawPath(mPath, mPathPaint);
        canvas.drawText(box.data + "",
                box.x + Cons.BOX_WIDTH / 2,
                box.y + Cons.BOX_HEIGHT / 2 + 3 * OFFSET_OF_TXT_Y, mTxtPaint);
    }
}
5.更新绘制单体的点位

每次增删操作后更新一下点位

代码语言:javascript
复制
/**
 * 更新绘制单体的点位
 */
private void updatePosOfData() {
    for (int i = 0; i < mArrayBoxes.size(); i++) {
        int y = i / 8;//行坐标
        int x = i % 8;//列坐标
        ArrayBox box = mArrayBoxes.get(i);
        box.x = (Cons.BOX_WIDTH + OFFSET_X) * x;
        box.y = (Cons.BOX_HEIGHT + OFFSET_Y) * y;
        box.vY = 100;
        box.vX = 100;
    }
}
6.点击时动态更新选中值:
代码语言:javascript
复制
/**
 * 点击时动态更新选中值
 * @param downX 按下点X
 * @param downY 按下点Y
 */
private void updateSelectIndex(float downX, float downY) {
    float x = downX / (Cons.BOX_WIDTH + OFFSET_X) - 0.5f;
    float y = downY / (Cons.BOX_HEIGHT + OFFSET_Y) - 0.5f;
    if (x > -0.5 && y > -0.5) {
        int indexOfData = Math.round(y) * 8 + Math.round(x);//逆向求取点中的数据索引
        if (indexOfData < mArrayBoxes.size()) {
            mArrayBoxes.get(indexOfData).color = ColUtils.randomRGB();
            selectIndex = indexOfData;
        }
    }
}

四、操作按钮绘制:

注意:以下操作是在Activity中的点击回调中进行,调用了view层的方法,实现操作与视图分离

1.增加操作:
代码语言:javascript
复制
/**
 * 视图的数据操作接口方法--添加
 *
 * @param data 数据
 */
public void addData(E data) {
    ArrayBox<E> arrayBox = new ArrayBox<>(0, 0);
    arrayBox.data = data;
    mArrayBoxes.add(arrayBox);
    updatePosOfData();//更新一下点位
}

添加操作.gif

代码语言:javascript
复制
 * 视图的数据操作接口方法--根据索引添加
 *
 * @param index
 * @param data
 */
public void addDataById(int index, E data) {
    if (mArrayBoxes.size() > 0 && index < mArrayBoxes.size() && index >= 0) {
        ArrayBox<E> arrayBox = new ArrayBox<>(0, 0);
        arrayBox.data = data;
        mArrayBoxes.add(index, arrayBox);
        updatePosOfData();
    }
}

定点添加.gif


2.查询和更新操作
代码语言:javascript
复制
/**
 * 视图的数据操作接口方法--根据id查询操作
 * @param index
 * @return
 */
public E findData(int index) {
    if (mArrayBoxes.size() > 0 && index < mArrayBoxes.size() && index >= 0) {
        return mArrayBoxes.get(index).data;
    }
    return null;
}

/**
 * 更新数据
 * @param index 索引
 * @param data 数据
 */
public void setData(int index, E data) {
    if (mArrayBoxes.size() > 0 && index < mArrayBoxes.size() && index >= 0) {
        mArrayBoxes.get(index).data = data;
    }
}

set和定索引查询.gif

代码语言:javascript
复制
/**
 * 视图的数据操作接口方法--根据数据查询操作
 * @param data
 * @return
 */
public int[] findData(E data) {
    ArrayBox<E> arrayBox = new ArrayBox<>(0, 0);
    arrayBox.data = data;
    return mArrayBoxes.getIndex(arrayBox);
}

定值查询获取索引.gif


3.删除操作:
1)删除的核心方法:
代码语言:javascript
复制
/**
 * 视图的数据操作接口方法--移除末尾
 */
public void removeData() {
    if (mArrayBoxes.size() > 0) {
        mArrayBoxes.remove();
        updatePosOfData();
    }
}
/**
 * 视图的数据操作接口方法--定索引删除操作
 *
 * @param index 索引
 */
public void removeData(int index) {
    if (mArrayBoxes.size() > 0 && index < mArrayBoxes.size() && index >= 0) {
        //更新后面的索引
        for (int i = index; i < mArrayBoxes.size(); i++) {
            mArrayBoxes.get(i).index -= 1;
        }
        mArrayBoxes.remove(index);
        selectIndex = -1;
        updatePosOfData();
    }
}
2)删除有个移除动画,ValueAnimate来帮忙
代码语言:javascript
复制
//初始化时间流ValueAnimator
mAnimator = ValueAnimator.ofFloat(0, 1);
mAnimator.setRepeatCount(-1);
mAnimator.setDuration(2000);
mAnimator.setRepeatMode(ValueAnimator.REVERSE);
mAnimator.setInterpolator(new LinearInterpolator());
mAnimator.addUpdateListener(animation -> {
    updateBall();//更新小球位置
    invalidate();
});
3)更新选中单体信息:updateBall
代码语言:javascript
复制
/**
 * 更新小球
 */
private void updateBall() {
    if (mArrayBoxes.size() <= 0 && selectIndex < 0) {
        return;
    }
    ArrayBox ball = mArrayBoxes.get(selectIndex);
    ball.x += ball.vX;
    ball.y += ball.vY;
    if (ball.y > 600) {//大于600就执行移除
        if (mOnCtrlClickListener != null) {
            mOnCtrlClickListener.onRemoveByIndex(this);//移除监听放在这里了!!
            mAnimator.pause();//暂停ValueAnimator
        }
    }
}
代码语言:javascript
复制
//点击的监听中修改:
 case 3://删除尾部---这里将移除的选中对象设为最后一个
     selectIndex = mArrayBoxes.size() - 1;
     mAnimator.start();//开启Animator

删除和定点删除.gif

4.联合测试:
代码语言:javascript
复制
private void contactTest() {
    IChart<ArrayBox<E>> contactArr = new ArrayChart<>();
    contactArr.add(new ArrayBox<E>((E) "toly1"));
    contactArr.add(new ArrayBox<E>((E) "toly2"));
    contactArr.add(new ArrayBox<E>((E) "toly3"));
    contactData(selectIndex, contactArr);
}

public void contactData(int index, IChart<ArrayBox<E>> chart) {
    mArrayBoxes.contact(index, chart);
    updatePosOfData();
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018.11.23 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、先绘制操作界面:
    • 1.自定义View:ArrayView
      • 2.把后面要用的画笔准备一下:
        • 3.准备小球的信息
          • 3.绘制小圆球:
          • 三、小球的点击事件(区域判断)
            • 1.有请吾王麾下十二战神之一:审断之神(JudgeMan.java)
              • 2.先写一下回调监听接口:OnCtrlClickListener
                • 3.触摸事件获取主动点:
                  • 4.Activity使用接口:
                  • 三、正文来了,绘制数据结构:
                    • 1.可绘制对象单体:使用数据结构单体的父类
                      • 2.数组表结构单体的绘图承载对象:
                        • 3.绘制数组的长度个空白矩形
                          • 1)如何根据索引确定点位
                          • 2)绘制数组的长度个空白矩形
                        • 4.绘制表结构
                          • 5.更新绘制单体的点位
                            • 6.点击时动态更新选中值:
                            • 四、操作按钮绘制:
                              • 1.增加操作:
                                • 2.查询和更新操作
                                  • 3.删除操作:
                                    • 1)删除的核心方法:
                                    • 2)删除有个移除动画,ValueAnimate来帮忙
                                    • 3)更新选中单体信息:updateBall
                                  • 4.联合测试:
                                  领券
                                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档