BezierDemo开源项目的学习

来源:互联网 发布:淘宝上有纯粮食酒吗 编辑:程序博客网 时间:2024/06/06 03:00

多看多学涨姿势,no zuo nuo die做暖男

1、概述

国际惯例,首先感谢一下开源作者。

这个项目主要是实现实现qq红点拖拽的效果 地址在https://github.com/chenupt/BezierDemo

主要效果


梳理主要知识点

【1】贝塞尔曲线的使用

【2】动态添加view

【3】判断点击事件是否在指定区域


2、项目知识点分析

【2.1】贝塞尔曲线的使用


常用的有2阶贝塞尔曲线


Path方法中

quadTo(float x1, float y1, float x2, float y2)可以用来绘制2阶贝塞尔曲线

其中quadTo的前两个参数为控制点的坐标,后两个参数为终点坐标,至于起点默认是画布的左上角。通常我们会使用moveTo移动到我们需要的起点,这里的p0就是起点,(x1,y1)就是中点P1,(x2,y2)就是末端点P2。p1称之为锚点


还有三阶贝塞尔曲线

同样是Path方法中

cubicTo(float x1, float y1, float x2, float y2, float x3, float y3) 用来绘制三阶贝塞尔曲线

与quadTo类似,前四个参数表示两个控制点,最后两个参数表示终点。其实,(x1,y1)就是P1,(x2,y2)是P2,(x3,y3)是P3。p2,p3称之为锚点

【在该项目中的使用】

项目中使用二阶贝塞尔曲线,由于实现拖拽效果实际是固定一个点,拖拽过程中为一个点,发生贝塞尔曲线实际上为这俩个圆之间的切线,如下图

可以看出p1-p2和p3-p4俩条线段会产生贝塞尔曲线,锚点在圆心连线上

作者在calcute方法中做了处理

// 根据角度算出四边形的四个点        float offsetX = (float) (radius*Math.sin(Math.atan((y - startY) / (x - startX))));        float offsetY = (float) (radius*Math.cos(Math.atan((y - startY) / (x - startX))));        float x1 = startX - offsetX;        float y1 = startY + offsetY;        float x2 = x - offsetX;        float y2 = y + offsetY;        float x3 = x + offsetX;        float y3 = y - offsetY;        float x4 = startX + offsetX;        float y4 = startY - offsetY;        path.reset();        path.moveTo(x1, y1);        path.quadTo(anchorX, anchorY, x2, y2);        path.lineTo(x3, y3);        path.quadTo(anchorX, anchorY, x4, y4);        path.lineTo(x1, y1);

【2.2、动态添加view】

这里牵涉到LayoutParams

LayoutParams继承于Android.View.ViewGroup.LayoutParams.
       LayoutParams相当于一个Layout的信息包,它封装了Layout的位置、高、宽等信息。假设在屏幕上一块区域是由一个Layout占领的,如果将一个View添加到一个Layout中,最好告诉Layout用户期望的布局方式,也就是将一个认可的layoutParams传递进去。
       但LayoutParams类也只是简单的描述了宽高,宽和高都可以设置成三种值:
       1,一个确定的值;
       2,FILL_PARENT,即填满(和父容器一样大小);
       3,WRAP_CONTENT,即包裹住组件就好。

作者动态添加了俩个imageview,一个是表示消息的imageview一个是移除红点之后的气泡效果

在Init方法中

LayoutParams params = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); exploredImageView = new ImageView(getContext()); exploredImageView.setLayoutParams(params); exploredImageView.setImageResource(R.drawable.tip_anim); exploredImageView.setVisibility(View.INVISIBLE);  tipImageView = new ImageView(getContext()); tipImageView.setLayoutParams(params); tipImageView.setImageResource(R.drawable.skin_tips_newmessage_ninetynine);  addView(tipImageView); addView(exploredImageView); 

通过LayoutParams + addView完成动态添加控件,其实有时候xml无法满足时我们也可以通过动态控制view的方式来解决问题,建议还是熟悉一下代码写常用布局。

这里补充一下:

exploredImageView使用的是帧动画AnimationDrawable,这样可以模拟出连续的效果,使用也很简单,在drable文件夹中定义几个帧动画

<?xml version="1.0" encoding="utf-8"?><animation-list    xmlns:android="http://schemas.android.com/apk/res/android"    android:oneshot="true">    <item android:drawable="@drawable/idp" android:duration="300"/>    <item android:drawable="@drawable/idq" android:duration="300"/>    <item android:drawable="@drawable/idr" android:duration="300"/>    <item android:drawable="@drawable/ids" android:duration="300"/>    <item android:drawable="@drawable/idt" android:duration="300"/>    <item android:drawable="@android:color/transparent" android:duration="300"/></animation-list>

这样可以模拟出消息移除后气泡爆炸的效果

【2.3、判断点击事件是否在指定区域】

主要是使用到

View.getLocationInWindow(int[] location)
一个控件在其父窗口中的坐标位置
View.getLocationOnScreen(int[] location)
一个控件在其整个屏幕上的坐标位置

他们使用的模式都一样先new一个Rect

该项目中需要判断点击事件是否是在红色消息图片上

 if(event.getAction() == MotionEvent.ACTION_DOWN){            // 判断触摸点是否在tipImageView中            Rect rect = new Rect();            int[] location = new int[2];            tipImageView.getDrawingRect(rect);            tipImageView.getLocationOnScreen(location);            rect.left = location[0];            rect.top = location[1];            rect.right = rect.right + location[0];            rect.bottom = rect.bottom + location[1];            if (rect.contains((int)event.getRawX(), (int)event.getRawY())){                isTouch = true;            }








0 0
原创粉丝点击