前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android实现去哪儿携程地址互换效果

Android实现去哪儿携程地址互换效果

作者头像
砸漏
发布2020-11-05 11:15:29
6500
发布2020-11-05 11:15:29
举报
文章被收录于专栏:恩蓝脚本

昨天朋友项目中有个需求让我帮忙看看怎么搞,就跟去哪儿携程买机票时点中间按钮互换出发地和目的地的效果,当时一看觉得挺简单,用补间动画,在动画完成时设置给两边各textview互换值就好,做出来后发现效果不好,在最后互换值得时候会有闪烁,于是就用了一种较为麻烦的方法,不过效果是达到了,记录一下。gif效果不好。

这里写图片描述
这里写图片描述

内容

简单说下思路,在点击互换按钮后:

1、计算互换位置的需要的偏移量:

这里需要需要考虑的特殊地方就是左右两边有可能文字长度不一样,所以我在textview外面套了一层相对布局.画个图来说明吧.布局最外层是个水平的线性布局,中间一个button,两边各一个相对布局宽度0dp权重1,里面的textview宽度都是包裹内容的.

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

2、获取两侧textview的坐标及绘图缓存,创建镜像view,隐藏两侧的textview,这里直接看下面代码就好啦,需要注意的是Y坐标要减去状态栏高度.

3、隐藏两侧的textview,开启镜像view的属性动画,在结束时互换textview的值,显示出textview,移除镜像view,释放资源.

代码

代码语言:javascript
复制
public class AddressActivity extends AppCompatActivity {
private TextView mTvLeft;
private TextView mTvRight;
private Button mBtn;
private RelativeLayout mRlLeft;
private RelativeLayout mRlRight;
private WindowManager mWindowManager;
private int[] mLeftLocation;
private int[] mRightLocation;
private Bitmap mLeftCacheBitmap;
private Bitmap mRightCacheBitmap;
private LinearLayout mLl;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_address);
mWindowManager = getWindowManager();
mTvLeft = (TextView) findViewById(R.id.tv_left);
mTvRight = (TextView) findViewById(R.id.tv_right);
mRlLeft = (RelativeLayout) findViewById(R.id.rl_left);
mRlRight = (RelativeLayout) findViewById(R.id.rl_right);
mLl = (LinearLayout) findViewById(R.id.ll);
mBtn = (Button) findViewById(R.id.btn);
mBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
textAnim();
mBtn.setEnabled(false);
}
});
}
/**
* 左边tv的镜像view
*/
private ImageView copyViewLeft;
/**
* 右边tv的镜像view
*/
private ImageView copyViewRight;
/**
* 获取tv的属性,计算偏移量,
*/
private void textAnim() {
//获取tv控件距离父控件的位置
int leftRight = mTvLeft.getRight();
int rightLeft = mTvRight.getLeft();
//包裹右侧tv距离父控件的距离
int rlRight = mRlRight.getRight();
int rlLeft = mRlRight.getLeft();
//在哪里设的padding就要用哪个控件来获取padding值
int paddingStart = mLl.getPaddingStart();
Log.d("AddressActivity", "paddingStart:" + paddingStart);
//左侧textview需要移动的距离
int leftOffset = rlRight - leftRight - paddingStart;
//右侧textview需要移动的距离
int rightOffset = rlLeft + rightLeft - paddingStart;
//创建出镜像view
createCopyView();
//隐藏掉两边的tv
mTvLeft.setVisibility(View.INVISIBLE);
mTvRight.setVisibility(View.INVISIBLE);
//开启镜像view的动画
leftAnim(leftOffset,mLeftLocation[0]);
rightAnim(rightOffset,mRightLocation[0]);
}
/**
* 创建镜像view
*/
private void createCopyView(){
mLeftLocation = new int[2];
mRightLocation = new int[2];
//获取相对window的坐标
mTvLeft.getLocationInWindow(mLeftLocation);
mTvRight.getLocationInWindow(mRightLocation);
//获取左边tv的缓存bitmap
mTvLeft.setDrawingCacheEnabled(true);
mLeftCacheBitmap = Bitmap.createBitmap(mTvLeft.getDrawingCache());
mTvLeft.destroyDrawingCache();
//获取右边tv的缓存bitmap
mTvRight.setDrawingCacheEnabled(true);
mRightCacheBitmap = Bitmap.createBitmap(mTvRight.getDrawingCache());
mTvRight.destroyDrawingCache();
//创建出两个镜像view
copyViewLeft = createCopyView(mLeftLocation[0], mLeftLocation[1], mLeftCacheBitmap);
copyViewRight = createCopyView(mRightLocation[0], mRightLocation[1], mRightCacheBitmap);
//释放bitmap资源...这我不确定是不是这么做
mLeftCacheBitmap = null;
mRightCacheBitmap = null;
}
/**
* 左侧镜像view的动画
* @param offset 偏移量
* @param defX  原始位置的x
*/
private void leftAnim(int offset, final int defX){
ValueAnimator leftAnimV = ValueAnimator.ofInt(0,offset);
leftAnimV.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
int animatedValue = (int) valueAnimator.getAnimatedValue();
WindowManager.LayoutParams layoutParams = (WindowManager.LayoutParams) copyViewLeft.getLayoutParams();
//往右边移动所以x是变大的
layoutParams.x = defX + animatedValue;
mWindowManager.updateViewLayout(copyViewLeft,layoutParams);
}
});
leftAnimV.setDuration(400);
leftAnimV.start();
//左侧动画监听
leftAnimV.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
//改变值
String s = mTvLeft.getText().toString();
mTvLeft.setText(mTvRight.getText().toString());
mTvRight.setText(s);
mTvLeft.setVisibility(View.VISIBLE);
mWindowManager.removeView(copyViewLeft);
copyViewLeft = null;
mBtn.setEnabled(true);
}
});
}
/**
* 右侧镜像view动画
* @param offset 偏移量
* @param defX  原始位置的x
*/
private void rightAnim(int offset, final int defX){
ValueAnimator rightAnimV = ValueAnimator.ofInt(0,offset);
rightAnimV.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
int animatedValue = (int) valueAnimator.getAnimatedValue();
WindowManager.LayoutParams layoutParams = (WindowManager.LayoutParams) copyViewRight.getLayoutParams();
layoutParams.x = defX - animatedValue;
mWindowManager.updateViewLayout(copyViewRight,layoutParams);
}
});
rightAnimV.setDuration(400);
rightAnimV.start();
rightAnimV.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
mTvRight.setVisibility(View.VISIBLE);
mWindowManager.removeView(copyViewRight);
copyViewRight = null;
}
});
}
/**
* 创建镜像view
*
* @param x
* @param y
* @param bitmap
*/
private ImageView createCopyView(int x, int y, Bitmap bitmap) {
WindowManager.LayoutParams mLayoutParams = new WindowManager.LayoutParams();
mLayoutParams.format = PixelFormat.TRANSLUCENT;   //图片之外其他地方透明
mLayoutParams.gravity = Gravity.TOP | Gravity.LEFT;
mLayoutParams.x = x; //设置imageView的原点
mLayoutParams.y = y - getStatusHeight(this);
mLayoutParams.alpha = 1f;        //设置透明度
mLayoutParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
mLayoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
mLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
ImageView copyView = new ImageView(this);
copyView = new ImageView(this);
copyView.setImageBitmap(bitmap);
mWindowManager.addView(copyView, mLayoutParams); //添加该iamgeView到window
return copyView;
}
/**
* 获取状态栏的高度
* @param context
* @return
*/
private static int getStatusHeight(Context context) {
int statusHeight = 0;
Rect localRect = new Rect();
((Activity) context).getWindow().getDecorView().getWindowVisibleDisplayFrame(localRect);
statusHeight = localRect.top;
if (0 == statusHeight) {
Class<?  localClass;
try {
localClass = Class.forName("com.android.internal.R$dimen");
Object localObject = localClass.newInstance();
int i5 = Integer.parseInt(localClass.getField("status_bar_height").get(localObject).toString());
statusHeight = context.getResources().getDimensionPixelSize(i5);
} catch (Exception e) {
e.printStackTrace();
}
}
return statusHeight;
}
}

以上就是本文的全部内容,希望对大家的学习有所帮助。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020-09-11 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档