android缩放组件,Android实现控件的缩放移动功能

本文详细介绍了如何在Android中实现控件的缩放和移动功能。通过一个自定义的DragScaleView组件,结合触摸事件ACTION_DOWN、ACTION_MOVE和ACTION_POINTER_DOWN,实现了单指拖动、双指缩放的交互效果。文章包含关键代码示例,包括布局设置、自定义控件的触摸事件处理以及计算手指间距离的方法。

上篇文章给大家介绍了 Android控件实现图片缩放功能,需要的朋友点击查看。

1.简介

话不多说先来张效果图

677ef93d145aebc98263e676c101f989.gif

控件缩放移动.gif

上面的gif中,依次进行了拖动——>触摸右上角放大,缩小——>触摸上方与右测边缘——>双指放大缩小。

2 使用步骤

2.1 布局。外层一个LinearLayout,里面一个自定义的控件DragScaleView,为了能够更清楚的看到控件的变化过程,就给控件加了一个灰色带虚线的边框bg_dashgap。

layout文件

android:orientation="vertical"

android:id="@+id/root"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:background="#80ce3d3a"

android:gravity="center_horizontal"

android:fitsSystemWindows="true">

android:id="@+id/hair_dv"

android:src="@drawable/ic_sure"

android:background="@drawable/bg_dashgap"

android:adjustViewBounds="true"

android:layout_marginLeft="50dp"

android:layout_marginTop="10dp"

android:layout_width="100dp"

android:layout_height="120dp"

android:clickable="true"/>

在drawable文件夹下的bg_dashgap.xml

android:bottomLeftRadius="8dp"

android:bottomRightRadius="8dp"

android:radius="15dp"

android:topLeftRadius="8dp"

android:topRightRadius="8dp" />

android:dashGap="4dp"

android:dashWidth="4dp"

android:width="2dp"

android:color="@color/my_gery" />

2.2 自定义的控件

单指触摸:

当ACTION_DOWN时如果坐标为1.2.3.4四个区域,则对View进行相应的左上/右上/左下/右下拉伸;

当ACTION_DOWN时如果坐标为5.6.7.8四个区域,则分别对上/右/下/左四个方向进行拉伸;

当ACTION_DOWN时如果坐标为9这个区域,则对View进行移动;

a989e1a7e951bbccf65ec2ce45b160dc.png

双指触摸:

先计算出触摸时双指的距离,float oriDist=distance(event);

再得到双指离开屏幕的距离,float newDist =distance(event);

得到两者之间的比例 float scale = newDist / oriDist;

计算双指间距离的方法

/**

* 计算两个手指间的距离

* @param event 触摸事件

* @return 放回两个手指之间的距离

*/

private float distance(MotionEvent event) {

float x = event.getX(0) - event.getX(1);

float y = event.getY(0) - event.getY(1);

return (float) Math.sqrt(x * x + y * y);//两点间距离公式

}

自定义的控件

onTouch(View v, MotionEvent event)的触摸事件中代码块

c1ec8f108fc7d444e53f6d2821eae270.png

image.png

其他的关键地方,代码中都有比较详细的注释了。思路就是

触摸监听

判断不同情况---getDirection(v, (int) event.getX(), (int) event.getY())

计算得到新的oriLeft, oriTop, oriRight, oriBottom

重新绘制---v.layout(oriLeft, oriTop, oriRight, oriBottom)

3 DragScaleView 的完整代码

public class DragScaleView extends android.support.v7.widget.AppCompatImageView implements View.OnTouchListener {

protected int screenWidth;

protected int screenHeight;

protected int lastX;

protected int lastY;

private int oriLeft;

private int oriRight;

private int oriTop;

private int oriBottom;

private int dragDirection;

private static final int TOP = 0x15;

private static final int LEFT = 0x16;

private static final int BOTTOM = 0x17;

private static final int RIGHT = 0x18;

private static final int LEFT_TOP = 0x11;

private static final int RIGHT_TOP = 0x12;

private static final int LEFT_BOTTOM = 0x13;

private static final int RIGHT_BOTTOM = 0x14;

private static final int TOUCH_TWO = 0x21;

private static final int CENTER = 0x19;

private int offset = 0; //可超出其父控件的偏移量

protected Paint paint = new Paint();

private static final int touchDistance = 80; //触摸边界的有效距离

// 初始的两个手指按下的触摸点的距离

private float oriDis = 1f;

/**

* 初始化获取屏幕宽高

*/

protected void initScreenW_H() {

screenHeight = getResources().getDisplayMetrics().heightPixels - 40;

screenWidth = getResources().getDisplayMetrics().widthPixels;

}

public DragScaleView(Context context, AttributeSet attrs, int defStyle) {

super(context, attrs, defStyle);

setOnTouchListener(this);

initScreenW_H();

}

public DragScaleView(Context context, AttributeSet attrs) {

super(context, attrs);

setOnTouchListener(this);

initScreenW_H();

}

public DragScaleView(Context context) {

super(context);

setOnTouchListener(this);

initScreenW_H();

}

@Override

protected void onDraw(Canvas canvas) {

super.onDraw(canvas);

paint.setColor(Color.GRAY);

paint.setStrokeWidth(4.0f);

paint.setStyle(Paint.Style.STROKE);

}

@Override

public boolean onTouch(View v, MotionEvent event) {

setBackgroundResource(R.drawable.bg_dashgap);

int action = event.getAction()& MotionEvent.ACTION_MASK;

if (action == MotionEvent.ACTION_DOWN) {

oriLeft = v.getLeft();

oriRight = v.getRight();

oriTop = v.getTop();

oriBottom = v.getBottom();

lastY = (int) event.getRawY();

lastX = (int) event.getRawX();

dragDirection = getDirection(v, (int) event.getX(),

(int) event.getY());

}

if (action == MotionEvent.ACTION_POINTER_DOWN){

oriLeft = v.getLeft();

oriRight = v.getRight();

oriTop = v.getTop();

oriBottom = v.getBottom();

lastY = (int) event.getRawY();

lastX = (int) event.getRawX();

dragDirection = TOUCH_TWO;

oriDis = distance(event);

}

// 处理拖动事件

delDrag(v, event, action);

invalidate();

return false;

}

/**

* 处理拖动事件

*

* @param v

* @param event

* @param action

*/

protected void delDrag(View v, MotionEvent event, int action) {

switch (action) {

case MotionEvent.ACTION_MOVE:

int dx = (int) event.getRawX() - lastX;

int dy = (int) event.getRawY() - lastY;

switch (dragDirection) {

case LEFT: // 左边缘

left(v, dx);

break;

case RIGHT: // 右边缘

right(v, dx);

break;

case BOTTOM: // 下边缘

bottom(v, dy);

break;

case TOP: // 上边缘

top(v, dy);

break;

case CENTER: // 点击中心-->>移动

center(v, dx, dy);

break;

case LEFT_BOTTOM: // 左下

left(v, dx);

bottom(v, dy);

break;

case LEFT_TOP: // 左上

left(v, dx);

top(v, dy);

break;

case RIGHT_BOTTOM: // 右下

right(v, dx);

bottom(v, dy);

break;

case RIGHT_TOP: // 右上

right(v, dx);

top(v, dy);

break;

case TOUCH_TWO: //双指操控

float newDist =distance(event);

float scale = newDist / oriDis;

//控制双指缩放的敏感度

int distX = (int) (scale*(oriRight-oriLeft)-(oriRight-oriLeft))/50;

int distY = (int) (scale*(oriBottom-oriTop)-(oriBottom-oriTop))/50;

if (newDist>10f){//当双指的距离大于10时,开始相应处理

left(v, -distX);

top(v, -distY);

right(v, distX);

bottom(v, distY);

}

break;

}

if (dragDirection != CENTER) {

v.layout(oriLeft, oriTop, oriRight, oriBottom);

}

lastX = (int) event.getRawX();

lastY = (int) event.getRawY();

break;

case MotionEvent.ACTION_UP:

case MotionEvent.ACTION_POINTER_UP:

dragDirection = 0;

break;

}

}

/**

* 触摸点为中心->>移动

*

* @param v

* @param dx

* @param dy

*/

private void center(View v, int dx, int dy) {

int left = v.getLeft() + dx;

int top = v.getTop() + dy;

int right = v.getRight() + dx;

int bottom = v.getBottom() + dy;

if (left < -offset) {

left = -offset;

right = left + v.getWidth();

}

if (right > screenWidth + offset) {

right = screenWidth + offset;

left = right - v.getWidth();

}

if (top < -offset) {

top = -offset;

bottom = top + v.getHeight();

}

if (bottom > screenHeight + offset) {

bottom = screenHeight + offset;

top = bottom - v.getHeight();

}

Log.d("raydrag", left+" "+top+" "+right+" "+bottom+" "+dx);

v.layout(left, top, right, bottom);

}

/**

* 触摸点为上边缘

*

* @param v

* @param dy

*/

private void top(View v, int dy) {

oriTop += dy;

if (oriTop < -offset) {

//对view边界的处理,如果子view达到父控件的边界,offset代表允许超出父控件多少

oriTop = -offset;

}

if (oriBottom - oriTop - 2 * offset < 200) {

oriTop = oriBottom - 2 * offset - 200;

}

}

/**

* 触摸点为下边缘

*

* @param v

* @param dy

*/

private void bottom(View v, int dy) {

oriBottom += dy;

if (oriBottom > screenHeight + offset) {

oriBottom = screenHeight + offset;

}

if (oriBottom - oriTop - 2 * offset < 200) {

oriBottom = 200 + oriTop + 2 * offset;

}

}

/**

* 触摸点为右边缘

*

* @param v

* @param dx

*/

private void right(View v, int dx) {

oriRight += dx;

if (oriRight > screenWidth + offset) {

oriRight = screenWidth + offset;

}

if (oriRight - oriLeft - 2 * offset < 200) {

oriRight = oriLeft + 2 * offset + 200;

}

}

/**

* 触摸点为左边缘

*

* @param v

* @param dx

*/

private void left(View v, int dx) {

oriLeft += dx;

if (oriLeft < -offset) {

oriLeft = -offset;

}

if (oriRight - oriLeft - 2 * offset < 200) {

oriLeft = oriRight - 2 * offset - 200;

}

}

/**

* 获取触摸点flag

*

* @param v

* @param x

* @param y

* @return

*/

protected int getDirection(View v, int x, int y) {

int left = v.getLeft();

int right = v.getRight();

int bottom = v.getBottom();

int top = v.getTop();

if (x < touchDistance && y < touchDistance) {

return LEFT_TOP;

}

if (y < touchDistance && right - left - x < touchDistance) {

return RIGHT_TOP;

}

if (x < touchDistance && bottom - top - y < touchDistance) {

return LEFT_BOTTOM;

}

if (right - left - x < touchDistance && bottom - top - y < touchDistance) {

return RIGHT_BOTTOM;

}

if (x < touchDistance) {

return LEFT;

}

if (y < touchDistance) {

return TOP;

}

if (right - left - x < touchDistance) {

return RIGHT;

}

if (bottom - top - y < touchDistance) {

return BOTTOM;

}

return CENTER;

}

/**

* 计算两个手指间的距离

*

* @param event 触摸事件

* @return 放回两个手指之间的距离

*/

private float distance(MotionEvent event) {

float x = event.getX(0) - event.getX(1);

float y = event.getY(0) - event.getY(1);

return (float) Math.sqrt(x * x + y * y);//两点间距离公式

}

}

总结

以上所述是小编给大家介绍的Android控件的缩放移动功能,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对脚本之家网站的支持!

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值