您的位置:首页 > 移动开发 > Android开发

Android自定义View之布局(layout)缩放

2017-02-20 11:53 309 查看
需求:手指滑动布局放大缩小移动,其子控件也跟着放大缩小。

系统自带有放大缩小的控件:ZoomControls.控制一张图片的放大缩小很简单。但这不满足我们的需求。今天我们来完成对布局的放大缩小还有移动。先看效果图:





1,首先准备工作:导入jar包,并add.



2,自定义PowerFullLayout继承FrameLayout ,注释都有 :

package com.skyworth.publicdisplay.view;

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;

/**
* ${DESC}
* author: gyq
* create at 2017/2/17 11:17
*/
public class PowerFullLayout 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;

public  boolean isScale = false;
private float scale;
private float preScale = 1;// 默认前一次缩放比例为1

public PowerFullLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}

public PowerFullLayout(Context context, AttributeSet attrs) {
this(context, attrs,0);
}

public PowerFullLayout(Context context) {
this(context,null);
}

private void init(Context context) {
mDragHelper = ViewDragHelper.create(this, callback);
mScaleGestureDetector = new ScaleGestureDetector(context,
new ScaleGestureListener());

}

@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);

return isScale;
}

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=true;
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 - (previousSpan - currentSpan) / 1000;
} else {
// 放大
scale = preScale + (currentSpan - previousSpan) / 1000;
}
// 缩放view
if (scale > 0.5) {
ViewHelper.setScaleX(PowerFullLayout.this, scale);// x方向上缩放
ViewHelper.setScaleY(PowerFullLayout.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();// 记录双指缩放后的时间
}
}
}


声明了一个变量:isScale,使用时要定义值。判断布局是否拦截此事件。

@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
super.onInterceptTouchEvent(ev);

return isScale;
}


3,使用:项目中我使用了类似开关的一个imageview的点击事件,来判断是否拦截事件。看代码:

windowLyt = (PowerFullLayout) findViewById(R.id.view_content);
mScale = (ImageView)findViewById(R.id.iv_scale);
mScale.setImageResource(R.drawable.scale_normal);
mScale.setSelected(!mScale.isSelected());

...
//imageview的点击事件
case R.id.iv_scale :
if (!mScale.isSelected()) {
windowLyt.isScale = false;
mScale.setImageResource(R.drawable.scale_normal);

} else if (mScale.isSelected()) {
windowLyt.isScale = true;
mScale.setImageResource(R.drawable.scale_press);
}
mScale.setSelected(!mScale.isSelected());
break;
...


4,布局文件:

<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="vertical">

<com.skyworth.publicdisplay.view.PowerFullLayout
android:id="@+id/view_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="1px"
android:paddingLeft="2px"
android:paddingTop="1px" />
</LinearLayout>


写博客的初心,其实就是记录一些在项目中使用到的一些技术,总结这些技术,方便今后阅读。

jar包下载地址:

http://download.csdn.net/download/duoduo_11011/9758507
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: