连线9宫格可实现手势密码等

 

最近一直想写一片视图的绘制过程,一张图,从测量布局到绘制,真的会的人也不用看,不会的人吧看完也不懂..尴尬。

这几天项目用到手势密码,网上下载了改了改。发现晚上很多都是自己从头画到底,很多带的功能不少,但是实际开发中就很尴尬。自己有想到了个实现方法,闲来没事搞了下,感觉可行分享出来。

这个使用的时候必须注意要给LinGesturePassword设置上背景,否则不会调用的的onDraw,主要是父类组件的一个特性,父类容器是用来发子类的所以没背景是不会调用的的onDraw。

这里要使用的时候添加的子类必须实现LinGesturePassword.ZhuangTai接口的三个方法,这样滑动才会改变,这里为了方便英语学渣的我直接没用使用有道查询,有强迫的人可以修改。这里我还主要标记了一下onLayout方法,这是父类的一个布局方法,有的时候是很方便的,自定义视图不自己写也要理解,不然怎么魔改别人的代码。

public class LinGesturePassword extends LinearLayout {
    float xy[] = new float[2];
    List<float[]> list = new ArrayList<>();
    List<Integer> lintp = new ArrayList<>();//保存密码id
    WanChengHuiDiao wanChengHuiDiao;
    private int lineColor = 0xFF378FC9;
    private int lineColorCuo = 0xFF378FC9;
    private int linStrokeWidth=10;
    private boolean isTouch = true;
    private boolean cuowu=false;

    public LinGesturePassword(Context context) {
        super(context);
    }

    public LinGesturePassword(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

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

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public LinGesturePassword(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }


    @Override
    public void onDraw(Canvas canvas) {
        Log.e("aaa", "运行拉啦啦啦");
        super.onDraw(canvas);
        drawAllLine(canvas);

    }


    /**
     * 关闭手势密码
     * @param touch
     */
    public void setTouch(boolean touch) {
        isTouch = touch;
    }

    public void setWanChengHuiDiao(WanChengHuiDiao wanChengHuiDiao) {
        this.wanChengHuiDiao = wanChengHuiDiao;
    }

    /**
     * 线条颜色
     * @param lineColor
     */

    public void setLineColor(int lineColor) {
        this.lineColor = lineColor;
    }

    /**
     * 选择错误后的线条颜色
     * @param lineColorCuo
     */
    public void setLineColorCuo(int lineColorCuo) {
        this.lineColorCuo = lineColorCuo;
    }

    /**
     * 设置线条粗细
     * @param linStrokeWidth
     */
    public void setLinStrokeWidth(int linStrokeWidth) {
        this.linStrokeWidth = linStrokeWidth;
    }

    private void drawAllLine(Canvas canvas) {
        Paint mPaint = new Paint();
        canvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG));
        mPaint.setAntiAlias(true);
        mPaint.setFilterBitmap(true);
        if(cuowu) {
            mPaint.setColor(lineColorCuo);
        }else {
            mPaint.setColor(lineColor);
        }
        mPaint.setStrokeWidth(linStrokeWidth);
        for (int i = 0; i < list.size(); i++) {
            if (i == list.size() - 1) {
                canvas.drawLine(list.get(i)[0], list.get(i)[1], xy[0], xy[1], mPaint);
            } else {
                canvas.drawLine(list.get(i)[0], list.get(i)[1], list.get(i + 1)[0], list.get(i + 1)[1], mPaint);
            }

        }

    }


    /**
     * 控制子控件的换行
     */
    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        int cellWidth = 0;//宽度偏差
        int columns = 0;//保存每排放的第几个view
        int y = 0;      //高度偏移量
        int maxy = 0;   //最大高度
        int count = getChildCount();//子view数量
        int gw = getMeasuredWidth() / 3;//获取宽度1/3这里主要是我一排放三个,看需求可以改成变量
        for (int j = 0; j < count; j++) {
            final View childView = getChildAt(j);
            // 获取子控件Child的宽高
            int w = childView.getMeasuredWidth();
            int h = childView.getMeasuredHeight();
            // 计算子控件的顶点坐标
            int left = (gw - w) / 2 + cellWidth;
            cellWidth += gw;//下一一个位置
            int top = y + (gw - w) / 2;
            // 布局子控件
            maxy = Math.max(gw, maxy);
            columns++;
            childView.layout(left, top, left + w, top + h);
            //判断一排是否到三个了,到三个换行
            if (columns >= 3) {
                cellWidth = 0;
                y += maxy;
                maxy = 0;
                columns = 0;
            }

        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        float[] fxy;
        if (isTouch) {
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:

                    chongZhi();
                    cuowu=false;
                    fxy = jx(event.getX(), event.getY());
                    if (fxy != null) {
                        list.add(fxy);
                        xy[0] = event.getX();
                        xy[1] = event.getY();
                    }
                    break;
                case MotionEvent.ACTION_MOVE:
                    fxy = jx(event.getX(), event.getY());
                    if (fxy != null) {
                        list.add(fxy);
                    }
                    xy[0] = event.getX();
                    xy[1] = event.getY();
                    break;
                case MotionEvent.ACTION_UP:
                    if (wanChengHuiDiao == null) {
                        list.clear();
                        lintp.clear();
                    } else {
                        wanChengHuiDiao.wanCheng(lintp);
                    }
                    break;
            }
            postInvalidate();
            return true;
        } else {
            return false;
        }
    }

    /**
     * 判断滑动的点是否和子类交叉
     * @param x
     * @param y
     * @return
     */

    public float[] jx(float x, float y) {
        int count = getChildCount();
        for (int j = 0; j < count; j++) {
            View childView = getChildAt(j);
            boolean t = true;
            for (int i = 0; i < lintp.size(); i++) {
                if (lintp.get(i) == j) {
                    t = false;
                    break;
                }
            }
            if (t) {
                if (childView.getX() < x && childView.getX() + childView.getWidth() > x) {
                    if (childView.getY() < y && childView.getY() + childView.getHeight() > y) {
                        lintp.add(j);
                        if (childView instanceof ZhuangTai) {
                            ((ZhuangTai) childView).xuanZhong();
                        }
                        return new float[]{childView.getX() + childView.getWidth() / 2, childView.getY() + childView.getHeight() / 2};
                    }
                }
            }
        }
        return null;
    }

    /**
     * 重置界面
     */
    public void chongZhi() {
        int count = getChildCount();
        for (int j = 0; j < count; j++) {
            View childView = getChildAt(j);
            if (childView instanceof ZhuangTai) {
                ((ZhuangTai) childView).weiXuanZhong();
            }
        }
        list.clear();
        lintp.clear();
        postInvalidate();

    }

    /**
     * 密码错误
     */
    public void  cuoWuJieMina(){
        cuowu=true;
        int count = getChildCount();
        for (int j = 0; j < count; j++) {
            View childView = getChildAt(j);
            if (childView instanceof ZhuangTai) {
                ((ZhuangTai) childView).cuoWu();
            }
        }
        postInvalidate();
    }

    public interface ZhuangTai {
        void xuanZhong();

        void cuoWu();

        void weiXuanZhong();
    }

    public interface WanChengHuiDiao {
        void wanCheng(List<Integer> list);
    }
}

 

随便实现的一个子类,正常用的ImageView的也不错看需求了,现在这个实现很难看,你可以找设计设置几张图完事,项目在接口放里面自己画也可,感觉还是跟要UI图方便......

public class Textvvvv extends TextView implements LinGesturePassword.ZhuangTai {
    public Textvvvv(Context context) {
        super(context);
    }

    public Textvvvv(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

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

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public Textvvvv(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }


    @Override
    public void xuanZhong() {
        setText("选中了");
        setBackgroundColor(0xFF378FC9);
    }

    @Override
    public void cuoWu() {
        setText("选择错误");
        setBackgroundColor(0xFFff0000);
    }

    @Override
    public void weiXuanZhong() {
        setText("未选中");
        setBackgroundColor(0xFF3ab826);
    }
}

布局文件随便加就行自动布局,但是要设置高度DP的话基本不会出现什么大的布局问题。这个视图的是现实根据父视图大小来实现平均的,可以改变LinGesturePassword的宽度设置居中然后会还看点,fLinGesturePassword的宽度必须大于三个的TextView的总宽度,不然就没间距了或者重叠

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <com.ag.text.myapplication.LinGesturePassword
        android:id="@+id/lin1"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#fff"
        android:layout_margin="10dp"
        android:orientation="vertical">

        <com.ag.text.myapplication.Textvvvv
            android:layout_width="80dp"
            android:layout_height="80dp"
            android:background="#FF3ab826"
            android:text="Hello World!"
            android:layout_marginTop="50dp"

            />
        <com.ag.text.myapplication.Textvvvv
            android:layout_width="80dp"
            android:layout_height="80dp"
            android:background="#FF3ab826"
            android:text="Hello World!"
            android:layout_marginTop="50dp"

            />
        <com.ag.text.myapplication.Textvvvv
            android:layout_width="80dp"
            android:layout_height="80dp"
            android:background="#FF3ab826"
            android:text="Hello World!"
            android:layout_marginTop="50dp"

            />
        <com.ag.text.myapplication.Textvvvv
            android:layout_width="80dp"
            android:layout_height="80dp"
            android:background="#FF3ab826"
            android:text="Hello World!"
            android:layout_marginTop="50dp"

            />
        <com.ag.text.myapplication.Textvvvv
            android:layout_width="80dp"
            android:layout_height="80dp"
            android:background="#FF3ab826"
            android:text="Hello World!"
            android:layout_marginTop="50dp"

            />
        <com.ag.text.myapplication.Textvvvv
            android:layout_width="80dp"
            android:layout_height="80dp"
            android:background="#FF3ab826"
            android:text="Hello World!"
            android:layout_marginTop="50dp"

            />
        <com.ag.text.myapplication.Textvvvv
            android:layout_width="80dp"
            android:layout_height="80dp"
            android:background="#FF3ab826"
            android:text="Hello World!"
            android:layout_marginTop="50dp"

            />
        <com.ag.text.myapplication.Textvvvv
            android:layout_width="80dp"
            android:layout_height="80dp"
            android:background="#FF3ab826"
            android:text="Hello World!"
            android:layout_marginTop="50dp"

            />
        <com.ag.text.myapplication.Textvvvv
            android:layout_width="80dp"
            android:layout_height="80dp"
            android:background="#FF3ab826"
            android:text="Hello World!"
            android:layout_marginTop="50dp"

            />
        <com.ag.text.myapplication.Textvvvv
            android:layout_width="80dp"
            android:layout_height="80dp"
            android:background="#FF3ab826"
            android:text="Hello World!"
            android:layout_marginTop="50dp"

            />

    </com.ag.text.myapplication.LinGesturePassword>

</LinearLayout>

使用

public class MainActivity extends AppCompatActivity {

    LinGesturePassword lin1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        lin1=findViewById(R.id.lin1);
//        lin1.setLineColor();//线条颜色
//        lin1.setLineColorCuo();//错误线条颜色
        lin1.setLinStrokeWidth(20);//线条粗度
        lin1.setWanChengHuiDiao(new LinGesturePassword.WanChengHuiDiao() {
            @Override
            public void wanCheng(List<Integer> list) {
                String pw="";
                for (int i = 0; i < list.size(); i++) {
                    pw+=list.get(i);
                }
                Log.e("aaa","密码"+pw);
//                lin1.cuoWuJieMina();//密码错误是调用
//                lin1.chongZhi();//重置界面
            }
        });

    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.e("main","main"+event.getAction());
        return super.onTouchEvent(event);
    }

gitee可能会跟新呵呵~~

https://gitee.com/axshuai/hand_gesture_unlock代码地址 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值