Skip to content

Instantly share code, notes, and snippets.

@arakuma
Created June 25, 2013 03:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save arakuma/5855678 to your computer and use it in GitHub Desktop.
Save arakuma/5855678 to your computer and use it in GitHub Desktop.
A simple dynamic layout tool.
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.view.animation.Animation;
import android.view.animation.LinearInterpolator;
import android.view.animation.Animation.AnimationListener;
/**
* 对View进行动态layout的工具类
* @author siwei1986@gmail.com
*
*/
public class DynamicLayouter {
/**
* View隐藏时的移动方向
* @author siwei1986@gmail.com
*
*/
public enum Orientation{
TOP,
BOTTOM,
LEFT,
RIGHT
}
/**
* 目标View
*/
private View mView;
/**
* 移动方向
*/
private Orientation mOrientation;
/**
* 上次记录的touch位置
*/
float mLastPos = 0.0f;
/**
* 显示范围低侧
*/
private int mBoundLow;
/**
* 显示范围高侧
*/
private int mBoundHigh;
/**
* 是否手动设置的范围
*/
private boolean mIsManualBound;
/**
* 构造函数
* @param view
* @param orientation
*/
public DynamicLayouter(View view, Orientation orientation, int boundLow, int boundHigh){
mView = view;
mBoundLow = boundLow;
mBoundHigh = boundHigh;
mIsManualBound = true;
}
/**
* 构造函数
* @param view
* @param orientation
* @param extraOffset
*/
public DynamicLayouter(View view, Orientation orientation){
mView = view;
mOrientation = orientation;
mView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
mView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
int screenWidth = DeviceInfo.getScreenWidth();
int screenHeight = DeviceInfo.getScreenHeight();
// 这本来想用嵌套三目运算符写的,虽然代码会少些但看起来实在痛苦,改成if-else了
if(isHorizontal()){
if(followsTouchDirection()){
// 左
mBoundLow = -mView.getWidth();
mBoundHigh = 0;
}
else {
// 右
mBoundLow = screenWidth - mView.getWidth();
mBoundHigh = screenWidth;
}
}
else {
if(followsTouchDirection()){
// 上
mBoundLow = -mView.getHeight();
mBoundHigh = 0;
}
else {
// 下
mBoundLow = screenHeight - mView.getHeight();
mBoundHigh = screenHeight;
}
}
}
});
}
/**
* 发出一个touch event进行处理
* @param event
*/
public void feedMotionEvent(MotionEvent event){
int action = event.getAction() & MotionEvent.ACTION_MASK;
switch (action) {
case MotionEvent.ACTION_DOWN:
mLastPos = isHorizontal() ? event.getRawX() : event.getRawY();
break;
case MotionEvent.ACTION_MOVE:
float currentPos = isHorizontal() ? event.getRawX() : event.getRawY();
int movedDistance = (int) (currentPos - mLastPos);
if(!followsTouchDirection()){
// 逆动方向需要将移动距离修正为反向位移
movedDistance = -movedDistance;
}
mLastPos = currentPos;
int newPos = movedDistance + (isHorizontal() ? mView.getLeft() : mView.getTop());
if(newPos >= mBoundLow && newPos <= mBoundHigh){
// 最多只能将控件侧边对齐到屏幕边缘,无论控件是否可见
shiftView(movedDistance);
}
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
int shownPartSize = isHorizontal()
? followsTouchDirection() ? mView.getRight() : mBoundHigh - mView.getLeft()
: followsTouchDirection() ? mView.getBottom() : mBoundHigh - mView.getTop();
// 显示的部分是否小于一半
int rangeSize = mIsManualBound
? mBoundHigh - mBoundLow
: isHorizontal() ? mView.getWidth() : mView.getHeight();
boolean isShownLessThanHalf = shownPartSize < rangeSize / 2;
// 需要移动的距离,显示的话要移动隐藏部分的尺寸,隐藏则是显示部分的尺寸
int translateX, translateY;
if(isHorizontal()){
translateX = isShownLessThanHalf ? -shownPartSize : rangeSize - shownPartSize;
translateY = 0;
if(!followsTouchDirection()){
translateX = -translateX;
}
}
else {
translateX = 0;
translateY = isShownLessThanHalf ? -shownPartSize : rangeSize - shownPartSize;
if(!followsTouchDirection()){
translateY = -translateY;
}
}
// 和最终目的地之间的距离就是移动的距离
final int destinationPosOffset = isHorizontal() ? translateX : translateY;
// 采用动画方式显隐
TranslateAnimation translateAnimation = new TranslateAnimation(translateX, 0, 0, translateY);
translateAnimation.setDuration(500);
translateAnimation.setFillAfter(true);
translateAnimation.setInterpolator(new LinearInterpolator());
translateAnimation.setAnimationListener(new AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {}
@Override
public void onAnimationRepeat(Animation animation) {}
@Override
public void onAnimationEnd(Animation animation) {
mView.clearAnimation();
shiftView(destinationPosOffset);
}
});
mView.startAnimation(shownAnimation);
default:
break;
}
}
/**
* 移动View
* @param offset 指定的位移
*/
private void shiftView(int offset){
if(isHorizontal()){
// 左右
shiftXBasedOnLeftOffset(mView, offset);
}
else {
// 上下
shiftYBasedOnTopOffset(mView, offset);
}
}
/**
* 判断是否水平方向移动
* @return 返回True,如果是左右方向显隐
*/
private boolean isHorizontal(){
return mOrientation == Orientation.LEFT || mOrientation == Orientation.RIGHT;
}
/**
* 判断View是否顺着touch移动方向而动
* @return 返回True,如果是上方或者左方显隐
*/
private boolean followsTouchDirection(){
return mOrientation == Orientation.TOP || mOrientation == Orientation.LEFT;
}
/**
* 移动view到指定的电,基于横纵轴位置
* @param view
* @param toX
* @param toY
*/
public static void shiftXYBasedOnLeftTop(View view, int toX, int toY){
view.layout(toX, toY, toX + view.getWidth(), toY + view.getHeight());
}
/**
* 移动view到指定的点,基于纵轴位移
* @param view
* @param toX
*/
public static void shiftYBasedOnTopOffset(View view, int offsetY) {
view.layout(view.getLeft(), view.getTop() + offsetY, view.getRight(), view.getTop() + view.getHeight() + offsetY);
}
/**
* 移动view到指定的点,基于纵轴上侧位置
* @param view
* @param toX
*/
public static void shiftYBasedOnTop(View view, int toY) {
view.layout(view.getLeft(), toY, view.getRight(), view.getHeight() + toY);
}
/**
* 移动view到指定的点,基于横轴位移
* @param view
* @param toX
*/
public static void shiftXBasedOnLeftOffset(View view, int offsetX) {
view.layout(view.getLeft() + offsetX, view.getTop(), view.getLeft() + view.getWidth() + offsetX, view.getBottom());
}
/**
* 移动view到指定的点,基于横轴左侧位置
* @param view
* @param toX
*/
public static void shiftXBasedOnLeft(View view, int toX) {
view.layout(toX, view.getTop(), view.getWidth() + toX, view.getBottom());
}
/**
* 移动view到指定的点,基于横轴右侧位置
*
* @param view
* @param toX
*/
public static void shiftXBasedOnRight(View view, int toX) {
view.layout(toX - view.getWidth(), view.getTop(), toX, view.getBottom());
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment