专栏首页Android知识点总结D2-Android自定义拉绳小控件

D2-Android自定义拉绳小控件

零、前言

[1].今天忙了大半天重构LogicCanvas库结果还是很令我满意的,LogicCanvas已经升级到V0.02了 [2].以前想过,以后我变厉害了,一定要写个小拉环,一个晚上总算捣哧出来了 [3].本控件绘图部分使用我的LogicCanvas绘图库,喜欢的话可以到github上看看,顺便给个star [4].动画使用我的NumGo库,由于绘图经常用,所以已经集成到LogicCanvas中了,单独NumGo的github地址 [5].本文主要讲的是绘制以及事件处理,回调处理,自定义属性就不演示了,可以根据前一篇自己写一下 [6].注释写得应该很清楚了,我就不废话了。准备瓜子花生米,往下看吧。

先看看效果:

拉环控件.gif


一、准备工作:

1.新建SwitchRopView继承自View:初始化NumGo
public class SwitchRopView extends View {

    public SwitchRopView(Context context) {
        this(context, null, 0);
    }

    public SwitchRopView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public SwitchRopView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    public void init() {
        mRunNum = new NumGo(false, -1, 2000).setOnUpdate(new NumGo.OnUpdate() {
            @Override
            public void onUpdate(float rate) {
                mRotateRate = rate;
                invalidate();
            }
        });
    }
}
2.dip2px方法
public float dip2px(Float dp) {
    if (dp != null) {
        final Float scale = getContext().getResources().getDisplayMetrics().density;
        return dp * scale + 0.5f;
    }
    return dp;
}

二、成员属性一览

大注释的都可以做成自定义属性,看你们的需要吧

//线的属性---------------------------------
/**
 * 线宽
 */
private float mRopWidth = dip2px(8f);
/**
 * 线高
 */
private float mRopHeight = dip2px(60f);
/**
 * 线的颜色
 */
private int mRopColor = 0xff76C5F5;
//斜线的属性---------------------------------
/**
 * 斜线宽
 */
private float mPieceWidth = dip2px(8.5f);
/**
 * 斜线高
 */
private float mPieceHeight = dip2px(5f);
/**
 * 斜线的个数
 */
private float mPieceCount = 5;
/**
 * 斜线的颜色
 */
private int mPieceColor = 0xffFBF579;
//圆圈的属性---------------------------------
/**
 * 圆圈半径
 */
private float mRingR = dip2px(10f);
/**
 * 圆圈厚度
 */
private float mRingB = dip2px(6f);
/**
 * 圆圈颜色
 */
private int mRingColor = 0xffC4C4BA;
//小圈的属性---------------------------------
/**
 * 小圆圈半径
 */
private float mDorR = dip2px(7f);
/**
 * 小圆圈厚度
 */
private float mDotB = dip2px(2f);
/**
 * 小圆圈颜色
 */
private int mDotColor = 0xffffffff;
private NumGo mRunNum;
private float mRotateRate;//旋转的分度值
Pos lastPos = new Pos(0, 0);//最后一次坐标点
long lastTimestamp = 0L;//最后一次的时间戳
float downHeight = 0;//下拉总量
boolean isMove = false;//是否移动
boolean isDown = false;//是否按下

三、绘制方法:onDraw

@Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        Painter painter = new Painter(canvas);
        //绘制线
        Shape rop = new ShapeLine().ps(
                new Pos(0, 0),
                new Pos(0, -mRopHeight),
                new Pos(0 + mRopWidth, -mRopHeight),
                new Pos(0 + mRopWidth, 0),
                new Pos(0, 0))
                .fs(mRopColor).p((2 * mRingR - mRopWidth) / 2, 0f);
        painter.draw(rop);
        //绘制斜线
        ShapeLine piece = new ShapeLine();
        piece.fs(mPieceColor);
        Pos p0 = new Pos(0, 0);
        Pos p1 = new Pos(0, -mPieceHeight);
        Pos p2 = new Pos(mPieceWidth, -mPieceWidth - mPieceHeight);
        Pos p3 = new Pos(mPieceWidth, -mPieceWidth);
        for (int i = 0; i < mPieceCount; i++) {
            piece.ps(p0, p1, p2, p3).p((2 * mRingR - mRopWidth) / 2, -mRopHeight / 5 * i);
            painter.draw(piece);
        }
        //绘制圆圈和点
        ShapeArc ring = new ShapeArc();
        ring.r(mRingR).ang(360f).b(mRingB).ss(mRingColor);
        ShapeArc rot = new ShapeArc();
        rot.r(mDorR).ang(45f).b(mDotB).rot(360 * mRotateRate).ss(mDotColor);
        painter.groupMove(mRingR, -mRopHeight - mRingR + 3, ring, rot);
        painter.draw(ring);
        painter.draw(rot);
    }

四、测量

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //测量
        setMeasuredDimension((int) (2 * mRingR), (int) dip2px(600f));
    }

五、事件监听

    /////////////////////////////////////////////拉绳拉下监听

    /**
     * 拉绳拉下监听
     */
    public interface OnRopDownListener {
        /**
         * 拉绳拉下回调函数
         * @param dataY 下移量
         */
        void ropDown(float dataY);
    }

    private OnRopDownListener mOnRopDownListener;

    public void setOnRopDownListener(OnRopDownListener onRopDownListener) {
        mOnRopDownListener = onRopDownListener;
    }

    /////////////////////////////////////////////拉绳松开监听

    /**
     * 拉绳松开监听
     */
    public interface OnRopUPListener {
        /**
         * 拉绳松开回调函数
         */
        void ropUp();
    }

    private OnRopUPListener mOnRopUPListener;

    public void setOnRopUPListener(OnRopUPListener onRopUPListener) {
        mOnRopUPListener = onRopUPListener;
    }

六、事件处理

    @Override
    public boolean onTouchEvent(MotionEvent event) {

        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN://按下
                mRunNum.go();//按下触发RunNum,使得小点旋转
                lastPos.x = event.getX();
                lastPos.y = event.getY();
                lastTimestamp = System.currentTimeMillis();
                mRingColor = ColUtils.randomRGB();//环设随机色
                isDown = true;
                break;
            case MotionEvent.ACTION_UP://抬起
                mRopHeight = dip2px(60f);//回复到原始高度
                mRunNum.end();//结束动画
                if (mOnRopUPListener != null && isMove) {//设置抬起监听
                    mOnRopUPListener.ropUp();//回调抬起函数
                    isMove = false;
                }
                downHeight = 0;
                isDown = false;
                invalidate();
                break;
            case MotionEvent.ACTION_MOVE://2

                float x = event.getX();
                float y = event.getY();
                Pos curPos = new Pos(x, y);//最后一次坐标点

                long curTimestamp = new Date().getTime();
                long t = curTimestamp - lastTimestamp;
                float dataY = curPos.y - lastPos.y;
                mRopHeight += dataY;
                downHeight += dataY;
                if (downHeight > 50) {//下拉高度大于50才算移动
                    isMove = true;
                    if (t > 50) {//时间大于50ms才切换颜色
                        mRopColor = ColUtils.randomRGB();
                    }
                }

                if (mOnRopDownListener != null) {//下拉过程中的监听
                    mOnRopDownListener.ropDown(downHeight);
                }
                lastPos = curPos;//更新位置
                lastTimestamp = curTimestamp;//更新时间
                break;
        }
        return true;
    }

七、Activity使用

public class RopActivity extends AppCompatActivity {
    @BindView(R.id.rop)
    SwitchRopView mRop;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_rop);
        ButterKnife.bind(this);

        mRop.setOnRopUPListener(new SwitchRopView.OnRopUPListener() {
            @Override
            public void ropUp() {
                ToastUtil.show(RopActivity.this, "已松开手");
            }
        });

    }
}

附录、布局文件:.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.toly1994.d.view.SwitchRopView
        android:id="@+id/rop"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="8dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>

</android.support.constraint.ConstraintLayout>

后记、

1.声明:

[1]本文由张风捷特烈原创,转载请注明 [2]欢迎广大编程爱好者共同交流 [3]个人能力有限,如有不正之处欢迎大家批评指证,必定虚心改正 [4]你的喜欢与支持将是我最大的动力

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • D11-Android自定义控件之动画篇3-插值器与估值器

    张风捷特烈
  • [番外]理一理Android多文件上传那点事

    张风捷特烈
  • Android自定义控件辅助利器之EventParser

    张风捷特烈
  • rancher下的kubernetes之一:构建标准化vmware镜像

    学习kubernetes的时候,我们需要在kubernetes环境下实战操作,然而kubernetes环境安装并不容器,现在通过rancher可以简化安装过程,...

    程序员欣宸
  • (三)Java高并发秒杀系统API之Web层开发

    SpringMvc默认就会默认去WEB-INF下查找默认规范的配置文件,像我这里配置的servlet-name是seckill-dispatchServlet的...

    Java团长
  • ubuntu 使用总结

    清华源: https://mirror.tuna.tsinghua.edu.cn/help/ubuntu/

    努力在北京混出人样
  • ubuntu linux 16.04虚拟机更新源,vmtools,编译cuckoo,make.sh转换unix编码格式

    战神伽罗
  • [ 利器篇 ] - Microsoft Surface Pro 系列安装 Ubuntu 16.04 系统

    Microsoft Surface Pro 系列一直是平板+PC中的强者,刷新了针对PC的看法。这次由于项目的需求搭建测试环境,需要使用Ubuntu 16.04...

    程序手艺人
  • docker ssh秘钥免密登录

    有一台跳板机,已经实现了免密登录后端服务器。但是我写了一个django项目,它是运行在容器中的,也需要免密登录后端服务器。

    py3study
  • 设计模式之外观模式

    小编自从毕业后开始做软件开发,做着做着发现不爽了,钱赚不了太多,头发也白了。于是拿着一点小资本,想着做点小生意。瞅着眼前的餐饮行业还不错,于是打算开一家餐馆。开...

    用户1205080

扫码关注云+社区

领取腾讯云代金券