缩放系列(三):一个可以手势缩放、拖拽、旋转的layout
弄了一个下午,终于搞出来了,PowerfulLayout
下面是一个功能强大的改造的例子:
可以实现以下需求:
1.两个手指进行缩放布局
2.所有子控件也随着缩放,
3.子控件该有的功能不能丢失(像button有可被点击的功能,缩放后不能丢失该功能)
相对上个例子,多了一个功能---
4.拖拽(平移)layout
运行效果图:http://pan.baidu.com/s/1geIoG8r
图片太大就不贴出来了。
布局文件test.xml、超级简单的
<?xml version="1.0" encoding="utf-8"?>
<com.example.testbitmapscale.PowerfulLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" > <FrameLayout
android:background="@drawable/home_tools"
android:layout_width="match_parent"
android:layout_height="match_parent" > <ImageButton
android:id="@+id/imageButton2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/selector_button1" />
</FrameLayout> </com.example.testbitmapscale.PowerfulLayout>
java代码:
MainActivity也是超级简单
public class MainActivity extends ActionBarActivity {
private View view;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// setContentView(R.layout.test);
view = View.inflate(this, R.layout.test, null);
setContentView(view);
}
// @Override
// public boolean onTouchEvent(MotionEvent event) {
// if (event.getPointerCount() > 1) {
// // 多点触控
// // 返回给ScaleGestureDetector来处理
// return mScaleGestureDetector.onTouchEvent(event);
// } else {
// // 单点触控
// switch (event.getAction()) {
// case MotionEvent.ACTION_DOWN:
// downX = (int) event.getX();
// downY = (int) event.getY();
// newHeight = view.getLayoutParams().height;
// newWidth = view.getLayoutParams().width;
//// int widthMeasureSpec =
//// View.MeasureSpec.makeMeasureSpec(2000,View.MeasureSpec.AT_MOST);
////
//// int heightMeasureSpec
//// =View.MeasureSpec.makeMeasureSpec(2000,View.MeasureSpec.AT_MOST);
////
//// view.measure(widthMeasureSpec,heightMeasureSpec);
////
//// newHeight = view.getMeasuredHeight();
////
//// newWidth = view.getMeasuredWidth();
// break;
// case MotionEvent.ACTION_MOVE:
// long currentTimeMillis = System.currentTimeMillis();
// if (currentTimeMillis - lastMultiTouchTime > 200) {
// // 双指触控后要等待200毫秒才能执行单指触控的操作,避免双指触控后出现颤抖的情况
// int moveX = (int) event.getX();// 移动手指的时候手指的x
// int moveY = (int) event.getY();// 移动手指的时候手指的y
// int deltaX = (int) (moveX - downX);
// int deltaY = (int) (moveY - downY);
// int newLeft = left + deltaX;// view的新left
// int newTop = top + deltaY;// view的新top
// int newRight = right + deltaX;// view的新right
// int newBottom = bottom + deltaY;// view的新bottom
//// int newWidth = (int) (preScale * originalWidth);
//// int newHeight = (int) (preScale * originalHeight);
//// if (deltaX>(newWidth-originalHeight)/2||deltaY>(newHeight-originalHeight)/2) {
//// return false;
//// }
// // int newWidth = view.getWidth();
// // int newHeight = view.getHeight();
// System.out.println("newWidth:" + newWidth + "newHeight:"
// + newHeight);
//// System.out.println(preScale);
// if (newLeft < originalWidth - newWidth) {
// newLeft = originalWidth - newWidth;
// newRight = newLeft + newWidth;
// }
// // if (newTop < originalHeight - newHeight){
// // newTop = originalHeight - newHeight;
// // newBottom= newTop+newHeight;
// // }
// // if(newRight>originalWidth){
// // newRight=originalWidth;
// // newLeft=newRight-newWidth;
// // }
// // if(newBottom>originalHeight){
// // newBottom=originalHeight;
// // newTop=newBottom-newHeight;
// // }
// view.layout(newLeft, newTop, newRight, newBottom);// 重新摆放view的位置
// } else {
// return false;
// }
//
// break;
// case MotionEvent.ACTION_UP:
// // 更新位置信息
// left = view.getLeft();
// top = view.getTop();
// right = view.getRight();
// bottom = view.getBottom();
// break;
//
// default:
// break;
// }
// return true;// 代表消费了事件
// }
// }
}
PowerfulLayout.java:
package com.example.testbitmapscale; import android.content.Context;
import android.support.v4.widget.ViewDragHelper;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
import android.widget.FrameLayout; import com.nineoldandroids.view.ViewHelper; public class PowerfulLayout extends FrameLayout {
// 屏幕宽高
private int screenHeight;
private int screenWidth;
private ViewDragHelper mDragHelper;
private long lastMultiTouchTime;// 记录多点触控缩放后的时间
private int originalWidth;// view宽度
private int originalHeight;// view高度
private ScaleGestureDetector mScaleGestureDetector = null;
// private View view;
private int downX;// 手指按下的x坐标值
private int downY;// 手指按下的y坐标值
private int left;// view的左坐标值
private int top;// view的上坐标值
private int right;// view的右坐标值
private int bottom;// view的下坐标值
private int newHeight;
private int newWidth; private float scale;
private float preScale = 1;// 默认前一次缩放比例为1 public PowerfulLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
} public PowerfulLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
} public PowerfulLayout(Context context) {
super(context);
init(context);
} private void init(Context context) {
mDragHelper = ViewDragHelper.create(this, callback);
mScaleGestureDetector = new ScaleGestureDetector(context,
new ScaleGestureListener()); // view.post(new Runnable() {
//
// @Override
// public void run() {
// left = view.getLeft();
// top = view.getTop();
// right = view.getRight();
// bottom = view.getBottom();
// originalWidth = view.getWidth();
// originalHeight = view.getHeight();
// }
// });
} @Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
screenWidth = getMeasuredWidth();
screenHeight = getMeasuredHeight();
} @Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
super.onInterceptTouchEvent(ev);
boolean b = mDragHelper.shouldInterceptTouchEvent(ev);// 由mDragHelper决定是否拦截事件,并传递给onTouchEvent
return b;
} private boolean needToHandle=true;
@Override
public boolean onTouchEvent(MotionEvent event) { int pointerCount = event.getPointerCount(); // 获得多少点
if (pointerCount > 1) {// 多点触控,
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
needToHandle=false;
break;
case MotionEvent.ACTION_MOVE: break;
case MotionEvent.ACTION_POINTER_2_UP://第二个手指抬起的时候
needToHandle=true;
break; default:
break;
}
return mScaleGestureDetector.onTouchEvent(event);//让mScaleGestureDetector处理触摸事件
} else {
long currentTimeMillis = System.currentTimeMillis();
if (currentTimeMillis - lastMultiTouchTime > 200&&needToHandle) {
// 多点触控全部手指抬起后要等待200毫秒才能执行单指触控的操作,避免多点触控后出现颤抖的情况
try {
mDragHelper.processTouchEvent(event);
} catch (Exception e) {
e.printStackTrace();
}
return true;
}
// }
}
return false;
} private ViewDragHelper.Callback callback = new ViewDragHelper.Callback() {
/**
* 用于判断是否捕获当前child的触摸事件
*
* @param child
* 当前触摸的子view
* @param pointerId
* @return true就捕获并解析;false不捕获
*/
@Override
public boolean tryCaptureView(View child, int pointerId) {
if (preScale > 1)
return true;
return false;
} /**
* 控制水平方向上的位置
*/
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) { if (left < (screenWidth - screenWidth * preScale) / 2)
left = (int) (screenWidth - screenWidth * preScale) / 2;// 限制mainView可向左移动到的位置
if (left > (screenWidth * preScale - screenWidth) / 2)
left = (int) (screenWidth * preScale - screenWidth) / 2;// 限制mainView可向右移动到的位置
return left;
} public int clampViewPositionVertical(View child, int top, int dy) { if (top < (screenHeight - screenHeight * preScale) / 2) {
top = (int) (screenHeight - screenHeight * preScale) / 2;// 限制mainView可向上移动到的位置
}
if (top > (screenHeight * preScale - screenHeight) / 2) {
top = (int) (screenHeight * preScale - screenHeight) / 2;// 限制mainView可向上移动到的位置
}
return top;
} }; public class ScaleGestureListener implements
ScaleGestureDetector.OnScaleGestureListener { @Override
public boolean onScale(ScaleGestureDetector detector) { float previousSpan = detector.getPreviousSpan();// 前一次双指间距
float currentSpan = detector.getCurrentSpan();// 本次双指间距
if (currentSpan < previousSpan) {
// 缩小
// scale = preScale-detector.getScaleFactor()/3;
scale = preScale - (previousSpan - currentSpan) / 1000;
} else {
// 放大
// scale = preScale+detector.getScaleFactor()/3;
scale = preScale + (currentSpan - previousSpan) / 1000;
}
// 缩放view
if (scale > 0.5) {
ViewHelper.setScaleX(PowerfulLayout.this, scale);// x方向上缩放
ViewHelper.setScaleY(PowerfulLayout.this, scale);// y方向上缩放
}
return false;
} @Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
// 一定要返回true才会进入onScale()这个函数
return true;
} @Override
public void onScaleEnd(ScaleGestureDetector detector) {
preScale = scale;// 记录本次缩放比例
lastMultiTouchTime = System.currentTimeMillis();// 记录双指缩放后的时间
}
} }
可以手势缩放、拖拽、旋转的layout应用场景,例子:qq侧滑菜单。侧滑的时候菜单中所有子控件跟随父控件从小变大,不过它不支持双指缩放,只是单指操作。链接:http://blog.csdn.net/qq_30948129/article/details/52282451
缩放系列(三):一个可以手势缩放、拖拽、旋转的layout的更多相关文章
- 每天一个JavaScript实例-html5拖拽
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content ...
- jQuery 学习笔记3 点击弹出一个div并允许拖拽移动
这里我看了下http://qings.blog.51cto.com/4857138/998878/ 的文章,感谢他的分享. 首先我们有一个a标签和一个div,div默认是不显示的,当用户点击时改为显示 ...
- canvas 图片拖拽旋转之二——canvas状态保存(save和restore)
引言 在上一篇日志“canvas 图片拖拽旋转之一”中,对坐标转换有了比较深入的了解,但是仅仅利用坐标转换实现的拖拽旋转,会改变canvas坐标系的状态,从而影响画布上其他元素的绘制.因此,这个时候需 ...
- canvas 图片拖拽旋转之一——坐标转换translate
引言 对canvas中绘制的图片进行旋转操作,需要使用ctx.translate变换坐标系,将图片旋转的基点设为坐标系的原点,然后ctx.rotate旋转. 这个时候,因为canvas坐标系发生了旋转 ...
- ztree使用系列四(ztree实现同级拖拽排序并将排序结果保存数据库)
ztree这个系列的最后一篇,也是ztree功能强大的体现之中的一个--排序功能. ztree能够实现全部节点之间任意的拖拽排序功能.我这里依据须要实现了仅仅同意同级之间任意拖拽排序,事实上原理都一样 ...
- 使用TypeScript给Vue 3.0写一个指令实现组件拖拽
最近在用vue3重构后台的一个功能.一个弹窗组件,弹出一个表单.然后点击提交. 早上运维突然跑过来问我,为啥弹窗挡住了下边的表格的数据,我添加的时候,都没法对照表格来看了.你必须给我解决一下. 我参考 ...
- 一个全新的Vue拖拽特性实现:“调整尺寸”部分
关于拖拽 CabloyJS提供了完备的拖拽特性,可以实现移动和调整尺寸两大类功能,这里对调整尺寸的开发进行阐述 关于移动的开发,请参见:拖拽:移动 演示 开发步骤 下面以模块test-party为例, ...
- 一个全新的Vue拖拽特性实现:“移动”部分
关于拖拽 CabloyJS提供了完备的拖拽特性,可以实现移动和调整尺寸两大类功能,这里对移动的开发进行阐述 关于调整尺寸的开发,请参见:拖拽:调整尺寸 演示 开发步骤 下面以模块test-party为 ...
- C# 图片盖章功能实现,支持拖拽-旋转-放缩-保存
实现图片盖章功能,在图片上点击,增加“图章”小图片,可以拖拽“图章”到任意位置,也可以点击图章右下角园框,令图片跟着鼠标旋转和放缩. 操作方法:1.点击增加“图章”2.选中移动图标3.点中右下角放缩旋 ...
随机推荐
- 4.当接口的请求方式为 application/json的时候时
1..当接口的请求方式为 application/json的时候时,使用抓包软件(fiddler)获取到这个接口, 其中的Inspectprs-TextView中的内容就是jmeter中Body Da ...
- django+celery+rabitmq
django 项目中的设置(proj代表项目目录) proj settings.py CELERY_BROKER_URL = 'amqp://guest:guest@localhost:5672/' ...
- 真实代理(RealProxy)在WCF中的运用
在WCF中,当我们在调用服务端的方法时,一般有两点需要考虑:1.捕获服务端的异常信息,记录日志:2.及时关闭会话信道,当调用超时或调用失败时及时中断会话信道.我们一般会像下面这样处理(以Calcula ...
- js-轮播图
<!DOCTYPE HTML> <html> <head> <meta http-equiv="content-type" charset ...
- 《JS权威指南学习总结--9.5 类和类型》
内容要点: 介绍了三种用以检测任意对象的类的技术,instanceof运算符.constructor属性,以及构造函数的名字. 但每种技术都不甚完美,本节总结了鸭式辩型,这种编程哲学更加关注对象可以完 ...
- CSS3秘笈复习:第八章
一.背景的所有属性: 属性 作用 可选项 1.background-image 定义一张图片 url(...) 2.background-repeat 控制重复 no-repeat | repeat- ...
- php基础(二)数组
本文主要内容来自w3cschool 在 PHP 中,有三种数组类型: 索引数组 - 带有数字索引的数组 关联数组 - 带有指定键的数组 多维数组 - 包含一个或多个数组的数组 PHP 索引数组 有两种 ...
- MVC3+EF4.1学习系列(三)-----排序 刷选 以及分页
上篇文章 已经做出了基本的增删改查 但这远远不足以应付实际的项目 今天讲下实际项目中 肯定会有的 排序 刷选 以及分页. 重点想多写点分页的 毕竟这个是任何时候都要有的 而且 我会尽量把这个 ...
- Caffe+Ubuntu14.04+CUDA7.5 环境搭建(新人向)指南
序 本文针对想学习使用caffe框架的纯新手,如果文中有错误欢迎大家指出. 由于我在搭建这个环境的时候参考了许多网上的教程,但是没有截图,所以文中图片大多来源于网络. 本文没有安装matlab的步骤, ...
- Openjudge-计算概论(A)-求特殊自然数
描述: 一个十进制自然数,它的七进制与九进制表示都是三位数,且七进制与九进制的三位数码表示顺序正好相反.编程求此自然数,并输出显示. 输入为1时,输出此自然数的十进制表达式:输入为2时,输出此自然数的 ...