Android實(shí)現(xiàn)去哪兒攜程地址互換效果
昨天朋友項(xiàng)目中有個(gè)需求讓我?guī)兔纯丛趺锤?,就跟去哪兒攜程買(mǎi)機(jī)票時(shí)點(diǎn)中間按鈕互換出發(fā)地和目的地的效果,當(dāng)時(shí)一看覺(jué)得挺簡(jiǎn)單,用補(bǔ)間動(dòng)畫(huà),在動(dòng)畫(huà)完成時(shí)設(shè)置給兩邊各textview互換值就好,做出來(lái)后發(fā)現(xiàn)效果不好,在最后互換值得時(shí)候會(huì)有閃爍,于是就用了一種較為麻煩的方法,不過(guò)效果是達(dá)到了,記錄一下。gif效果不好。

內(nèi)容
簡(jiǎn)單說(shuō)下思路,在點(diǎn)擊互換按鈕后:
1、計(jì)算互換位置的需要的偏移量:
這里需要需要考慮的特殊地方就是左右兩邊有可能文字長(zhǎng)度不一樣,所以我在textview外面套了一層相對(duì)布局.畫(huà)個(gè)圖來(lái)說(shuō)明吧.布局最外層是個(gè)水平的線性布局,中間一個(gè)button,兩邊各一個(gè)相對(duì)布局寬度0dp權(quán)重1,里面的textview寬度都是包裹內(nèi)容的.


2、獲取兩側(cè)textview的坐標(biāo)及繪圖緩存,創(chuàng)建鏡像view,隱藏兩側(cè)的textview,這里直接看下面代碼就好啦,需要注意的是Y坐標(biāo)要減去狀態(tài)欄高度.
3、隱藏兩側(cè)的textview,開(kāi)啟鏡像view的屬性動(dòng)畫(huà),在結(jié)束時(shí)互換textview的值,顯示出textview,移除鏡像view,釋放資源.
代碼
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的屬性,計(jì)算偏移量,
*/
private void textAnim() {
//獲取tv控件距離父控件的位置
int leftRight = mTvLeft.getRight();
int rightLeft = mTvRight.getLeft();
//包裹右側(cè)tv距離父控件的距離
int rlRight = mRlRight.getRight();
int rlLeft = mRlRight.getLeft();
//在哪里設(shè)的padding就要用哪個(gè)控件來(lái)獲取padding值
int paddingStart = mLl.getPaddingStart();
Log.d("AddressActivity", "paddingStart:" + paddingStart);
//左側(cè)textview需要移動(dòng)的距離
int leftOffset = rlRight - leftRight - paddingStart;
//右側(cè)textview需要移動(dòng)的距離
int rightOffset = rlLeft + rightLeft - paddingStart;
//創(chuàng)建出鏡像view
createCopyView();
//隱藏掉兩邊的tv
mTvLeft.setVisibility(View.INVISIBLE);
mTvRight.setVisibility(View.INVISIBLE);
//開(kāi)啟鏡像view的動(dòng)畫(huà)
leftAnim(leftOffset,mLeftLocation[0]);
rightAnim(rightOffset,mRightLocation[0]);
}
/**
* 創(chuàng)建鏡像view
*/
private void createCopyView(){
mLeftLocation = new int[2];
mRightLocation = new int[2];
//獲取相對(duì)window的坐標(biāo)
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();
//創(chuàng)建出兩個(gè)鏡像view
copyViewLeft = createCopyView(mLeftLocation[0], mLeftLocation[1], mLeftCacheBitmap);
copyViewRight = createCopyView(mRightLocation[0], mRightLocation[1], mRightCacheBitmap);
//釋放bitmap資源...這我不確定是不是這么做
mLeftCacheBitmap = null;
mRightCacheBitmap = null;
}
/**
* 左側(cè)鏡像view的動(dòng)畫(huà)
* @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();
//往右邊移動(dòng)所以x是變大的
layoutParams.x = defX + animatedValue;
mWindowManager.updateViewLayout(copyViewLeft,layoutParams);
}
});
leftAnimV.setDuration(400);
leftAnimV.start();
//左側(cè)動(dòng)畫(huà)監(jiān)聽(tīng)
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);
}
});
}
/**
* 右側(cè)鏡像view動(dòng)畫(huà)
* @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;
}
});
}
/**
* 創(chuàng)建鏡像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; //設(shè)置imageView的原點(diǎn)
mLayoutParams.y = y - getStatusHeight(this);
mLayoutParams.alpha = 1f; //設(shè)置透明度
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;
}
/**
* 獲取狀態(tài)欄的高度
* @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;
}
}
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android textview 實(shí)現(xiàn)長(zhǎng)按自由選擇復(fù)制功能的方法
下面小編就為大家?guī)?lái)一篇Android textview 實(shí)現(xiàn)長(zhǎng)按自由選擇復(fù)制功能的方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-04-04
android listview進(jìn)階實(shí)例分享
這篇文章主要介紹了android listview進(jìn)階實(shí)例分享,具有一定借鑒價(jià)值,需要的朋友可以參考下2018-01-01
Android中使用achartengine生成圖表的具體方法
這篇文章主要介紹了Android中使用achartengine生成圖表的具體方法,有需要的朋友可以參考一下2014-01-01
android10 隱藏SystemUI鎖屏下的多用戶圖標(biāo)的示例代碼
這篇文章主要介紹了android10 隱藏SystemUI鎖屏下的多用戶圖標(biāo),本文通過(guò)示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-12-12
Android 加載assets中的資源文件實(shí)例代碼
這篇文章主要介紹了Android 加載assets中的資源文件實(shí)例代碼的相關(guān)資料,這里附有實(shí)例代碼,需要的朋友可以參考下2017-01-01
讓Android應(yīng)用不被殺死(killer)的方法
這篇文章主要介紹了讓Android應(yīng)用不被殺死(killer)的方法,本文講解了實(shí)現(xiàn)方法和原理分析,需要的朋友可以參考下2015-04-04
朋友圈實(shí)現(xiàn)圖片+文字轉(zhuǎn)發(fā)功能(必看篇)
下面小編就為大家?guī)?lái)一篇朋友圈實(shí)現(xiàn)圖片+文字轉(zhuǎn)發(fā)功能(必看篇)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-03-03

