Android仿百度,高德地圖位置交換控制元件,水平or垂直交換控制元件位置
阿新 • • 發佈:2018-12-17
開始看到這個需求,準備使用檢視動畫 TranslateAnimation 來實現。但是把因為檢視動畫只是移動了檢視,控制元件的位置沒有改變,導致只能執行一次交換的動作,不能交換回來。逐放棄改用屬性動畫來實現。直接交換兩個控制元件的位置,交換後在將原來控制元件的值賦予交換後的控制元件。
垂直交換的動畫
if (startView.getTranslationY() ==0) { //頂部控制元件平移動畫 從當前座標0.0 移動到需要交換位置的控制元件Y座標(endView.getY())加底部控制元件的高度減去上邊控制元件的高度得到的差值(endView.getHeight() - startView.getHeight()) 為上下控制元件大小不一後也能正常位移 startAnimator = ObjectAnimator.ofFloat(startView, View.TRANSLATION_Y, startView.getTranslationY(), endView.getY() + (endView.getHeight() - startView.getHeight())); //底部控制元件平移動畫 從當前座標0.0 移動當前父佈局中的最底部替換了頂部佈局。 endAnimator = ObjectAnimator.ofFloat(endView, View.TRANSLATION_Y, endView.getTranslationY(), -endView.getY()); }else { //已經平移過後,將平移的距離回退回去 startAnimator = ObjectAnimator.ofFloat(startView, View.TRANSLATION_Y, startView.getTranslationY(), -startView.getY()); endAnimator = ObjectAnimator.ofFloat(endView, View.TRANSLATION_Y, endView.getTranslationY(), startView.getY()); }
如果業務需求使用水平排列的佈局,只需要將佈局中的控制元件水平排列,之後將交換的動畫Y軸全部替換成X軸,高度替換為寬度。
if (startView.getTranslationX() ==0) { //頂部控制元件平移動畫 從當前座標0.0 移動到需要交換位置的控制元件X座標(endView.getX())加底部控制元件的高度減去上邊控制元件的高度得到的差值(endView.getWidth() - startView.getWidth()) 為上下控制元件大小不一後也能正常位移 startAnimator = ObjectAnimator.ofFloat(startView, View.TRANSLATION_X, startView.getTranslationX(), endView.getX() + (endView.getWidth() - startView.getWidth())); //底部控制元件平移動畫 從當前座標0.0 移動當前父佈局中的最底部替換了頂部佈局。 endAnimator = ObjectAnimator.ofFloat(endView, View.TRANSLATION_X, endView.getTranslationX(), -endView.getX()); }else { //已經平移過後,將平移的距離回退回去 startAnimator = ObjectAnimator.ofFloat(startView, View.TRANSLATION_X, startView.getTranslationX(), -startView.getX()); endAnimator = ObjectAnimator.ofFloat(endView, View.TRANSLATION_X, endView.getTranslationX(), startView.getX()); }
控制元件的實現並不多,我就直接將完整的實現貼上在這,在獲取控制元件內容和儲存的物件的時候如果有更好的方法歡迎留言。
垂直交換控制元件的完整實現
import android.animation.Animator; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.content.Context; import android.os.Bundle; import android.os.Parcelable; import android.support.annotation.Nullable; import android.text.TextUtils; import android.util.AttributeSet; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; public class LocationExchangeViewextends LinearLayoutimplements View.OnClickListener { public interface OnViewChangeListener{ void onStartCallback(); void onEndCallback(); } private OnViewChangeListenerl; public TextViewstartLocationView, endLocationView; public ImageViewlocationExchangeBtn; public LinearLayoutlocationLayout; private boolean isChange; private OnClickListenerstartListener; private OnClickListenerendListener; public void setOnClickStartLocation(OnClickListener onClick){ startListener=onClick; startLocationView.setOnClickListener(onClick); } public void setOnClickEndLocation(OnClickListener onClick){ endListener=onClick; endLocationView.setOnClickListener(onClick); } public LocationExchangeView(Context context) { super(context); init(context); } public LocationExchangeView(Context context, AttributeSet attrs) { super(context, attrs); init(context); } public LocationExchangeView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context); } public void setOnListener(OnViewChangeListener l) { this.l = l; } public OnViewChangeListenergetListener() { return l; } private void init(Context context) { if (contextinstanceof OnViewChangeListener) l = (OnViewChangeListener) context; LayoutInflater.from(getContext()).inflate(R.layout.location_exchange_view, this); startLocationView = findViewById(R.id.start_location_view); endLocationView = findViewById(R.id.end_location_view); locationExchangeBtn = findViewById(R.id.location_exchange_btn); locationLayout = findViewById(R.id.location_layout); locationExchangeBtn.setOnClickListener(this); } public void setStartLocation(String address,T tag) { if (address !=null) { startLocationView.setText(address); startLocationView.setTag(tag); } } public void setEndLocation(String address,T tag) { if (address !=null) { endLocationView.setText(address); endLocationView.setTag(tag); } } public T getStartLocationTag()throws Exception{ return (T)startLocationView.getTag(); } public T getEndLocationTag()throws Exception{ return (T)endLocationView.getTag(); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.location_exchange_btn: startChange(startLocationView, endLocationView); break; } } //當前切換狀態,為了把監聽事件進行替換 private boolean nowState; private void startChange(final TextView startView, final TextView endView) { if (isChange) return; isChange =true; AnimatorSet set =new AnimatorSet(); ObjectAnimator startAnimator =null; ObjectAnimator endAnimator =null; //控制按鈕 180度旋轉動畫 ObjectAnimator iconAnimator = ObjectAnimator.ofFloat(locationExchangeBtn, View.ROTATION, locationExchangeBtn.getRotation(), locationExchangeBtn.getRotation() +180); //startView.getTranslationY() == 0 上下控制元件位置未發生改變 if (startView.getTranslationY() ==0) { //頂部控制元件平移動畫 從當前座標0.0 移動到需要交換位置的控制元件Y座標(endView.getY())加底部控制元件的高度減去上邊控制元件的高度得到的差值(endView.getHeight() - startView.getHeight()) 為上下控制元件大小不一後也能正常位移 startAnimator = ObjectAnimator.ofFloat(startView, View.TRANSLATION_Y, startView.getTranslationY(), endView.getY() + (endView.getHeight() - startView.getHeight())); //底部控制元件平移動畫 從當前座標0.0 移動當前父佈局中的最底部替換了頂部佈局。 endAnimator = ObjectAnimator.ofFloat(endView, View.TRANSLATION_Y, endView.getTranslationY(), -endView.getY()); }else { //已經平移過後,將平移的距離回退回去 startAnimator = ObjectAnimator.ofFloat(startView, View.TRANSLATION_Y, startView.getTranslationY(), -startView.getY()); endAnimator = ObjectAnimator.ofFloat(endView, View.TRANSLATION_Y, endView.getTranslationY(), startView.getY()); } /* if (startView.getTranslationX() == 0) { //頂部控制元件平移動畫 從當前座標0.0 移動到需要交換位置的控制元件X座標(endView.getX())加底部控制元件的高度減去上邊控制元件的高度得到的差值(endView.getWidth() - startView.getWidth()) 為上下控制元件大小不一後也能正常位移 startAnimator = ObjectAnimator.ofFloat(startView, View.TRANSLATION_X, startView.getTranslationX(), endView.getX() + (endView.getWidth() - startView.getWidth())); //底部控制元件平移動畫 從當前座標0.0 移動當前父佈局中的最底部替換了頂部佈局。 endAnimator = ObjectAnimator.ofFloat(endView, View.TRANSLATION_X, endView.getTranslationX(), -endView.getX()); } else { //已經平移過後,將平移的距離回退回去 startAnimator = ObjectAnimator.ofFloat(startView, View.TRANSLATION_X, startView.getTranslationX(), -startView.getX()); endAnimator = ObjectAnimator.ofFloat(endView, View.TRANSLATION_X, endView.getTranslationX(), startView.getX()); }*/ set.playTogether(startAnimator, endAnimator, iconAnimator); set.setDuration(500); set.addListener(new Animator.AnimatorListener() { @Override public void onAnimationStart(Animator animation) { //如果控制元件值為空則先將hint內容替換在進行動畫。頂部永遠是起點,底部永遠是終點。 if (TextUtils.isEmpty(startLocationView.getText())){ startLocationView.setHint(getResources().getText(R.string.setting_destination)); } if (TextUtils.isEmpty(endLocationView.getText())){ endLocationView.setHint(getResources().getText(R.string.input_origin)); } if (l!=null) l.onStartCallback(); } @Override public void onAnimationEnd(Animator animation) { isChange =false; //動畫結束後將控制元件的值賦值回原控制元件 TextView startView =startLocationView; startLocationView =endView; endLocationView = startView; if (nowState){ nowState=true; startLocationView.setOnClickListener(endListener); endLocationView.setOnClickListener(startListener); }else { nowState=false; startLocationView.setOnClickListener(startListener); endLocationView.setOnClickListener(endListener); } if (l!=null) l.onEndCallback(); Log.e("===start:", startLocationView.getText().toString()); Log.e("===end:", endLocationView.getText().toString()); } @Override public void onAnimationCancel(Animator animation) { } @Override public void onAnimationRepeat(Animator animation) { } }); set.start(); } @Nullable @Override protected ParcelableonSaveInstanceState() { Bundle bundle =new Bundle(); bundle.putParcelable("superState", super.onSaveInstanceState()); if (startLocationView.getText()!=null){ bundle.putString("startString",startLocationView.getText().toString()); } bundle.putParcelable("startObject", (Parcelable)startLocationView.getTag()); if (endLocationView.getText()!=null){ bundle.putString("endString",endLocationView.getText().toString()); } bundle.putParcelable("endObject", (Parcelable)endLocationView.getTag()); return bundle; } @Override protected void onRestoreInstanceState(Parcelable state) { if (stateinstanceof Bundle) { Bundle bundle = (Bundle) state; String startString=bundle.getString("startString"); if (!TextUtils.isEmpty(startString)){ startLocationView.setText(startString); }else { startLocationView.setText(""); } String endString=bundle.getString("endString"); if (!TextUtils.isEmpty(endString)){ endLocationView.setText(endString); }else { endLocationView.setText(""); } Object startObject=bundle.getParcelable("startObject"); startLocationView.setTag(startObject); Object endObject=bundle.getParcelable("endObject"); endLocationView.setTag(endObject); state = bundle.getParcelable("superState"); } super.onRestoreInstanceState(state); } }
佈局檔案 其中的一些顏色和圖片檔案需要自行替換
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/gray_round_corner_bg">
android:id="@+id/location_exchange_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:paddingLeft="15dp"
android:paddingRight="15dp"
android:paddingTop="10dp"
android:paddingBottom="10dp"
android:background="@null"
android:src="@drawable/exchange_img"/>
android:id="@+id/left_linear"
android:layout_width="10dp"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_marginTop="21dp"
android:orientation="vertical">
android:id="@+id/my_location_point_img"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:background="@drawable/shape_green_point" />
android:layout_width="30dp"
android:layout_height="32dp"
android:layout_gravity="center_horizontal"
android:background="@drawable/shape_line_gray_dash"
android:layerType="software">
android:id="@+id/destination_point_img"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:background="@drawable/shape_red_point" />
android:id="@+id/location_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:layout_toLeftOf="@id/location_exchange_btn"
android:layout_toRightOf="@id/left_linear"
android:orientation="vertical">
android:id="@+id/start_location_view"
android:layout_width="match_parent"
android:layout_height="30dp"
android:gravity="center_vertical"
android:ellipsize="end"
android:maxLines="1"
android:textSize="14dp"
android:hint="@string/input_origin"
android:clickable="true"/>
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:layout_marginTop="5dp"
android:layout_marginBottom="5dp"
android:background="@color/line_color">
android:id="@+id/end_location_view"
android:layout_width="match_parent"
android:layout_height="30dp"
android:gravity="center_vertical"
android:ellipsize="end"
android:textSize="14dp"
android:hint="@string/setting_destination"
android:maxLines="1"
android:clickable="true"/>
</RelativeLayout>