您好,登錄后才能下訂單哦!
昨天朋友項目中有個需求讓我幫忙看看怎么搞,就跟去哪兒攜程買機票時點中間按鈕互換出發地和目的地的效果,當時一看覺得挺簡單,用補間動畫,在動畫完成時設置給兩邊各textview互換值就好,做出來后發現效果不好,在最后互換值得時候會有閃爍,于是就用了一種較為麻煩的方法,不過效果是達到了,記錄一下。gif效果不好。
內容
簡單說下思路,在點擊互換按鈕后:
1、計算互換位置的需要的偏移量:
這里需要需要考慮的特殊地方就是左右兩邊有可能文字長度不一樣,所以我在textview外面套了一層相對布局.畫個圖來說明吧.布局最外層是個水平的線性布局,中間一個button,兩邊各一個相對布局寬度0dp權重1,里面的textview寬度都是包裹內容的.
2、獲取兩側textview的坐標及繪圖緩存,創建鏡像view,隱藏兩側的textview,這里直接看下面代碼就好啦,需要注意的是Y坐標要減去狀態欄高度.
3、隱藏兩側的textview,開啟鏡像view的屬性動畫,在結束時互換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的屬性,計算偏移量, */ 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; } }
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持億速云。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。