Android_ 照片选择区域功能实现(1)

return;
}
// 绘制 4 个角
for (Point point : mCropPoints) {
canvas.drawCircle(getViewPointX(point), getViewPointY(point), dp2px(POINT_RADIUS), mPointFillPaint);
canvas.drawCircle(getViewPointX(point), getViewPointY(point), dp2px(POINT_RADIUS), mPointPaint);
}
if (mShowEdgeMidPoint) {
setEdgeMidPoints();
// 中间锚点
// 绘制 4 条边上的中点
for (Point point : mEdgeMidPoints){
canvas.drawCircle(getViewPointX(point), getViewPointY(point), dp2px(POINT_RADIUS), mPointFillPaint);
canvas.drawCircle(getViewPointX(point), getViewPointY(point), dp2px(POINT_RADIUS), mPointPaint);
}
}
}

绘制 4 条边上的中点前,

先算出当前 4 条边上中点的位置

public void setEdgeMidPoints(){
// 中点不存在,就新建
if (mEdgeMidPoints == null){
mEdgeMidPoints = new Point[4];
for (int i = 0; i < mEdgeMidPoints.length; i++){
mEdgeMidPoints[i] = new Point();
}
}
// 维护 4 个顶点的位置,
// 通过顶点的位置,算出边上中点的位置

int len = mCropPoints.length;
for (int i = 0; i < len; i++){
// 为了避免极端情况,
// 采用 ( 坐标 + 距离的一半 ) 的方式

mEdgeMidPoints[i].set(mCropPoints[i].x + (mCropPoints[(i+1)%len].x - mCropPoints[i].x)/2,
mCropPoints[i].y + (mCropPoints[(i+1)%len].y - mCropPoints[i].y)/2);
}
}

2, 拖动

拖动分 2 种情况,角点拖拽,中点平移

8 个类型, 4 个角点拖拽,4 个中点平移

enum DragPointType{
LEFT_TOP,
RIGHT_TOP,
RIGHT_BOTTOM,
LEFT_BOTTOM,
TOP,
RIGHT,
BOTTOM,
LEFT;

// 判断是角点拖拽,不是中点平移
public static boolean isEdgePoint(DragPointType type){
return type == TOP || type == RIGHT || type == BOTTOM || type == LEFT;
}
}

移动的处理

@Override
public boolean onTouchEvent(MotionEvent event) {
int action = event.getAction();
boolean handle = true;
switch (action) {
case MotionEvent.ACTION_DOWN:
// 识别到,当前点
mDraggingPoint = getNearbyPoint(event);
if (mDraggingPoint == null) {
handle = false;
}
break;
case MotionEvent.ACTION_MOVE:
// 移动
toImagePointSize(mDraggingPoint, event);
break;
case MotionEvent.ACTION_UP:
// 手指抬起,
// 操作取消
mDraggingPoint = null;
break;
}
// 绘制
// 更新完位置后,刷新绘制
invalidate();
return handle || super.onTouchEvent(event);
}

识别到,当前点

private Point getNearbyPoint(MotionEvent event) {
// 判断 4 个角点,可用
if (checkPoints(mCropPoints)) {
for (Point p : mCropPoints) {
// 找出当前的点
if (isTouchPoint(p, event)) return p;
}
}
// 判断 4 个中点可用
if (checkPoints(mEdgeMidPoints)) {
for (Point p : mEdgeMidPoints){
// 找出当前的点
if (isTouchPoint(p, event)) return p;
}
}
return null;
}

找出当前的点,的方法

private static final float TOUCH_POINT_CATCH_DISTANCE = 15;

private boolean isTouchPoint(Point p, MotionEvent event){
float x = event.getX();
float y = event.getY();
float px = getViewPointX§;
float py = getViewPointY§;
double distance = Math.sqrt(Math.pow(x - px, 2) + Math.pow(y - py, 2));

// 也就是,判断距离
if (distance < dp2px(TOUCH_POINT_CATCH_DISTANCE)) {
return true;
}
return false;
}

2.1 ,角点拖拽

先介绍 4 个角点拖拽

private void toImagePointSize(Point dragPoint, MotionEvent event) {
if (dragPoint == null) {
return;
}
// 找出当前移动类型,
// 是角点拖拽,还是中点平移
DragPointType pointType = getPointType(dragPoint);

int x = (int) ((Math.min(Math.max(event.getX(), mActLeft), mActLeft + mActWidth) - mActLeft) / mScaleX);
int y = (int) ((Math.min(Math.max(event.getY(), mActTop), mActTop + mActHeight) - mActTop) / mScaleY);

// 判断可以移动
// …

if (DragPointType.isEdgePoint(pointType)){
// …
// 中点平移
} else {
// 角点拖拽
// 实现很简单,
// 更新就好了
dragPoint.y = y;
dragPoint.x = x;
}
}

找出当前移动类型,

是角点拖拽,还是中点平移

// 拿采集的点,找出对应的类型
private DragPointType getPointType(Point dragPoint){
if (dragPoint == null) return null;

DragPointType type;
// 看,是不是顶点 / 角点
if (checkPoints(mCropPoints)) {
for (int i = 0; i < mCropPoints.length; i++) {
if (dragPoint == mCropPoints[i]) {
// 找到了,直接返回
type = DragPointType.values()[i];
return type;
}
}
}
// 看,是不是中点
if (checkPoints(mEdgeMidPoints)) {
for (int i = 0; i < mEdgeMidPoints.length; i++){
if (dragPoint == mEdgeMidPoints[i]){
// 找到了,直接返回
type = DragPointType.values()[4+i];
return type;
}
}
}
return null;
}

2.2,中点平移

private void toImagePointSize(Point dragPoint, MotionEvent event) {
if (dragPoint == null) {
return;
}

DragPointType pointType = getPointType(dragPoint);

int x = // …
int y = // …

// 判断可以移动
// …

if (DragPointType.isEdgePoint(pointType)){
// 中点平移,
// 拿到的是,一个偏移向量
int xoff = x - dragPoint.x;
int yoff = y - dragPoint.y;
moveEdge(pointType, xoff, yoff);
} else {
// 角点拖拽
// …
}
}

拿到偏移向量,修改对应的两个顶点的坐标

private void moveEdge(DragPointType type, int xoff, int yoff){

面试复习笔记:

这份资料我从春招开始,就会将各博客、论坛。网站上等优质的Android开发中高级面试题收集起来,然后全网寻找最优的解答方案。每一道面试题都是百分百的大厂面经真题+最优解答。包知识脉络 + 诸多细节。
节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。

《960页Android开发笔记》

《1307页Android开发面试宝典》

包含了腾讯、百度、小米、阿里、乐视、美团、58、猎豹、360、新浪、搜狐等一线互联网公司面试被问到的题目。熟悉本文中列出的知识点会大大增加通过前两轮技术面试的几率。

《507页Android开发相关源码解析》

只要是程序员,不管是Java还是Android,如果不去阅读源码,只看API文档,那就只是停留于皮毛,这对我们知识体系的建立和完备以及实战技术的提升都是不利的。

真正最能锻炼能力的便是直接去阅读源码,不仅限于阅读各大系统源码,还包括各种优秀的开源库。
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!
04765457)]

《507页Android开发相关源码解析》

只要是程序员,不管是Java还是Android,如果不去阅读源码,只看API文档,那就只是停留于皮毛,这对我们知识体系的建立和完备以及实战技术的提升都是不利的。

真正最能锻炼能力的便是直接去阅读源码,不仅限于阅读各大系统源码,还包括各种优秀的开源库。
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值