———————————————————————
有需求者请加qq:136137465,非诚勿扰
(java 架构师全套教程,共760G, 让你从零到架构师,每月轻松拿3万)
01.高级架构师四十二个阶段高
02.Java高级系统培训架构课程148课时
03.Java高级互联网架构师课程
04.Java互联网架构Netty、Nio、Mina等-视频教程
05.Java高级架构设计2016整理-视频教程
06.架构师基础、高级片
07.Java架构师必修linux运维系列课程
08.Java高级系统培训架构课程116课时
(送:hadoop系列教程,java设计模式与数据结构, Spring Cloud微服务, SpringBoot入门)
——————————————————————–
1、应用的地方:如未读数据的清除等
2、这个控件要实现哪些功能呢?
1)拖拽超出范围时,断开了,此时我们松手,图标消失
2)拖拽超出范围时,断开了,此时我们把图标移动回去,图标恢复原样
3)拖拽没有超出范围时,此时我们松手,图标弹回去
3、如何实现:
1)我们先画个两个静态的圆圈,一个大的,一个小的
2)绘制中间连接的部分:
3)把静态的数值变成变量
4)不断地修改变量,重绘界面,就能动起来
1、创建自定义view
/**
* @描述 粘性控件
* @项目名称 App_imooc
* @包名 com.android.imooc.goo
* @类名 GooView
* @author chenlin
* @date 2015年6月2日 下午8:40:53
* @version 1.0
*/
public class GooView extends View {
public GooView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public GooView(Context context) {
this(context, null);
}
public GooView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setColor(Color.RED);
}
@Override
protected void onDraw(Canvas canvas) {
}
}
2、在onDraw里绘制个圆
private Paint mPaint;
private float mCircleCenter = 150f;
private float mRadius = 14f;//直径
private void init() {
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setColor(Color.RED);
}
@Override
protected void onDraw(Canvas canvas) {
canvas.drawCircle(mCircleCenter, mCircleCenter, mRadius, mPaint);
}
3、生成主页
/**
* @描述 主页
* @项目名称 App_imooc
* @包名 com.android.imooc.goo
* @类名 GooActivity
* @author chenlin
* @date 2015年6月2日 下午8:57:16
* @version 1.0
*/
public class GooActivity extends Activity {
private GooView mGooView;
@Override
protected void onCreate(Bundle savedInstanceState) {
requestWindowFeature(Window.FEATURE_NO_TITLE);
super.onCreate(savedInstanceState);
mGooView = new GooView(this);
setContentView(mGooView);
}
}
4、开始画拖拽的大圆
private float mMoveCircleCenter = 70f;
private float mMoveRadius = 20f;//直径
canvas.drawCircle(mMoveCircleCenter, mMoveCircleCenter, mMoveRadius, mPaint);
5、画拖拽的填充部分,这是重点,绘制使用drawPath
canvas.drawPath(path, mPaint);
但如何才能实现有弯曲的填充物呢?使用了path,
只要一个控制点,如图:
有两个控制点:如图:
在这里,我们先绘制一个这样的图,
p1到p2绘制一条贝塞尔曲线
p2到p3绘制直线
p3到p4绘制贝塞尔曲线
p4到p1绘制直线
如图:
代码实现:
// 画连接部分
Path path = new Path();
// 50, 250 p2
path.moveTo(250f, 250f);
// 150f, 300f填充物的中间点
// 50f, 250f p1
path.quadTo(150f, 300f, 50f, 250f);
// p3
path.lineTo(50f, 350f);
// p4
path.quadTo(150f, 300f, 250f, 350f);
//关闭后,会回到最开始的地方,形成封闭的图形
path.close();
canvas.drawPath(path, mPaint);
好了,现在我们会基本的绘制了,开始把这些点转为动态的吧!
如图:
1、把上的圆的点全部转化成float类型的点
PointF staticPointF = new PointF(mStaicCircleCenter, mStaicCircleCenter);
// 画小圆
canvas.drawCircle(staticPointF.x, staticPointF.y, mStaicRadius, mPaint);
PointF movewPointF = new PointF(mMoveCircleCenter, mMoveCircleCenter);
// 画移动的大圆
canvas.drawCircle(movewPointF.x, movewPointF.y, mMoveRadius, mPaint);
2、转化Path上面的点
我们分别使用两个集合存储静态的点与动态点
//存储静态的两个点
PointF[] staticPointFs = new PointF[] { new PointF(250f, 250f), new PointF(250f, 350f) };
//存储移动的两个点
PointF[] moviePointFs = new PointF[] { new PointF(50f, 250f), new PointF(50f, 350f) };
//控制点
PointF controlPointF = new PointF(150f, 300f);
// 画连接部分
Path path = new Path();
// 50, 250 p2
path.moveTo(staticPointFs[0].x, staticPointFs[0].y);
// 150f, 300f填充物的中间点
// 50f, 250f p1
path.quadTo(controlPointF.x, controlPointF.y, moviePointFs[0].x, moviePointFs[0].y);
// p3
path.lineTo(moviePointFs[1].x, moviePointFs[1].y);
// p4
path.quadTo(controlPointF.x, controlPointF.y, staticPointFs[1].x, staticPointFs[1].y);
// 关闭后,会回到最开始的地方,形成封闭的图形
path.close();
canvas.drawPath(path, mPaint);
3、接下来我们就是要把下面的曲型移动到上面两个圆圈之间,形成一个整体
在这里有,两个圆圈的中心点的坐标是已知的,半径也是知道的,现在就剩下求4个点的坐标了
第一个移动点的坐标如何求,看图
movePointfs[0].x = movePointf.x + mMoveRadius. cos(a);
movePointfs[0].y = movePointf.y - mMoveRadius. sin(a);
4、开始求得各个点
// 1、获得偏移量
float yOffset = mStaticCenter.y - mMovewCenter.y;
float xOffset = mStaticCenter.x - mMovewCenter.x;
// 2、有了偏移量就可以求出两点斜率了
Double lineK = 0.0;
if (xOffset != 0f) {
lineK = (double) (yOffset / xOffset);
}
// 3、通过工具求得两个点的集合
mMovewPointFs = GeometryUtil.getIntersectionPoints(mMovewCenter, mMoveRadius, lineK);
mStaticPointFs = GeometryUtil.getIntersectionPoints(mStaticCenter, mStaicRadius, lineK);
// 4、通过公式求得控制点
mControlPointF = GeometryUtil.getMiddlePoint(mStaticCenter, mMovewCenter);
1、复写onTouchEvent事件,记得在view里要返回true;
@Override
public boolean onTouchEvent(MotionEvent event) {
float downX = 0.0f;
float downY = 0.0f;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// 得到按下的坐标
downX = event.getRawX();
downY = event.getRawY();
// 更新移动的坐标
updateMoveCenter(downX, downY);
break;
case MotionEvent.ACTION_MOVE:
// 得到按下的坐标
downX = event.getRawX();
downY = event.getRawY();
// 更新移动的坐标
updateMoveCenter(downX, downY);
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
break;
}
return true;
}
/**
* 更新移动的点
*
* @param downX
* @param downY
*/
public void updateMoveCenter(float downX, float downY) {
mMovewCenter.set(downX, downY);
invalidate();
}
2、此时看,我们的手总是离大圆圈有一点距离,这个距离就是状态栏的高度,如何才能让手指在中间呢?
方法1:此时必须先得到状态栏的高度
/**
* 获取状态栏高度
*
* @param v
* @return
*/
public static int getStatusBarHeight(View v) {
if (v == null) {
return 0;
}
Rect frame = new Rect();
v.getWindowVisibleDisplayFrame(frame);
return frame.top;
}
如果画布进行了平移或旋转动画,我们必须在平移钱,保存,在绘制完成后恢复
canvas.save();
canvas.translate(0, -mBarHeight);
canvas.restore();
方法2:不使用getRawX,而是使用getX,这样的话就不存在状态栏的问题了
downX = event.getX();
downY = event.getY();
// 更新移动的坐标
updateMoveCenter(downX, downY);
3、当大圆圈移动到一定距离时,会断开,此时如果松手了,消失
怎么才能得到两个圆心的距离呢?我们以前学过勾股定理
就是:(y1-y2)的平方 + (x1-x2)的平方的和然后开根号
/**
* As meaning of method name. 获得两点之间的距离
*
* @param p0
* @param p1
* @return
*/
public static float getDistanceBetween2Points(PointF p0, PointF p1) {
float distance = (float) Math.sqrt(Math.pow(p0.y - p1.y, 2) + Math.pow(p0.x - p1.x, 2));
return distance;
}
4、当移动时,小圆圈的半径会随着拉动的距离变化,如何实现
// 获取固定圆半径(根据两圆圆心距离)
private float getTempStickRadius() {
float distance = GeometryUtil.getDistanceBetween2Points(mMovewCenter, mStaticCenter);
// if(distance> farestDistance){
// distance = farestDistance;
// }
distance = Math.min(distance, mMaxDistance);
// 0.0f -> 1.0f
float percent = distance / mMaxDistance;
// percent , 100% -> 20%
return ValueUtil.evalute(percent, mStaicRadius, mStaicRadius * 0.2f);
}
然后在 onDraw里把得到的值设置到
float tempStaticRadius = getTempStickRadius();
canvas.drawCircle(mStaticCenter.x, mStaticCenter.y, tempStaticRadius, mPaint);
5、现在实现到了一定距离后,断开,在onTouchevent的move事件里判断
//当超过最大值时断开
float distance = GeometryUtil.getDistanceBetween2Points(mMovewCenter, mStaticCenter);
if (distance > mMaxDistance) {
isOutRange = true;
invalidate();
}
然后在onDraw里判断
if (!isOutRange) {
//如果没有超出范围才绘制
}
6、超出范围后,是否消失的实现在MotionEvent.ACTION_UP里实现,这里有三种可能,上面已经说了
if (isOutRange) {
//1)拖拽超出范围时,断开了,此时我们松手,图标消失
// 当超过最大值时断开
distance = GeometryUtil.getDistanceBetween2Points(mMovewCenter, mStaticCenter);
if (distance > mMaxDistance) {
isDisappear = true;
invalidate();
}else {
//2)拖拽超出范围时,断开了,此时我们把图标移动回去,图标恢复原样
//就是把移动的圆圈设置到原来的静态圆圈里
updateMoveCenter(mStaticCenter.x, mStaticCenter.y);
}
}else {
//3)拖拽没有超出范围时,此时我们松手,图标弹回去
//得到固定的点
final PointF tempMovePointF = new PointF(mMovewCenter.x, mMovewCenter.y);
ValueAnimator vAnim = ValueAnimator.ofFloat(1.0f);
vAnim.addUpdateListener(new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float percent = animation.getAnimatedFraction();
//得到两点的
PointF pointF = GeometryUtil.getPointByPercent(tempMovePointF, mStaticCenter, percent);
updateMoveCenter(pointF.x, pointF.y);
}
});
vAnim.setInterpolator(new OvershootInterpolator(4));
vAnim.setDuration(500);
vAnim.start();
}
到此,这个控件基本完成了,
链接:http://pan.baidu.com/s/1nvKpyad 密码:rniy
———————————————————————
(java 架构师全套教程,共760G, 让你从零到架构师,每月轻松拿3万)
有需求者请进站查看,非诚勿扰
https://item.taobao.com/item.htm?spm=686.1000925.0.0.4a155084hc8wek&id=555888526201
01.高级架构师四十二个阶段高
02.Java高级系统培训架构课程148课时
03.Java高级互联网架构师课程
04.Java互联网架构Netty、Nio、Mina等-视频教程
05.Java高级架构设计2016整理-视频教程
06.架构师基础、高级片
07.Java架构师必修linux运维系列课程
08.Java高级系统培训架构课程116课时
(送:hadoop系列教程,java设计模式与数据结构, Spring Cloud微服务, SpringBoot入门)
——————————————————————–