Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> CoordinatorLayout 自定義Behavior

CoordinatorLayout 自定義Behavior

編輯:關於Android編程

先來看看最終的效果~~

這裡寫圖片描述

嗯。。一個是頭像上移的 另一個是模仿UC浏覽器的。<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxwPihQp6VgcaGjKcTjsrvKx8u1o6HT0Mj9v+61xMLwo6zU9cO01rvT0MG9v+6joaOho6GjoTwvcD4NCjxwPrK70qq8scLvoaOho6GjIMu1wcu007zytb3E0aOstdrSu7/uyse96cncuMXE7rXEwLKhozwvcD4NCjxwPrnY09pDb29yZGluYXRvckxheW91dKOs0tS8sM+1zbPUpMH0U2Nyb2xsQmVoYXZpb3LKudPDzfjJz9LUvLDT0LrctuDOxNXCPC9wPg0KPGgyIGlkPQ=="基礎概念">基礎概念

其實Behavior就是一個應用於View的觀察者模式,一個View跟隨者另一個View的變化而變化,或者說一個View監聽另一個View。

在Behavior中,被觀察View 也就是事件源被稱為denpendcy,而觀察View,則被稱為child。

開始自定義 難度1 Button與TextView的愛恨情仇

首先在布局文件中跟布局設置為CoordinatorLayout,裡面放一個Button和一個TextView。




    

這裡我們在Activity中做一些手腳,讓Button動起來(不要在意坐標這些細節)

  @Override protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_easy_behavior);
    findViewById(R.id.btn).setOnTouchListener(new View.OnTouchListener() {
      @Override public boolean onTouch(View v, MotionEvent event) {
        switch (event.getAction()){

          case MotionEvent.ACTION_MOVE:
            v.setX(event.getRawX()-v.getWidth()/2);
            v.setY(event.getRawY()-v.getHeight()/2);
            break;
        }
        return false;
      }
    });

  }

此時,Button已經可以跟隨手指移動了。

現在去自定義一個Behavior讓TextView跟隨Button一起動!

創建一個EasyBehavior類,繼承於Behavior

public class EasyBehavior extends CoordinatorLayout.Behavior {//這裡的泛型是child的類型,也就是觀察者View
  public EasyBehavior(Context context, AttributeSet attrs) {
    super(context, attrs);
  }

  @Override
  public boolean layoutDependsOn(CoordinatorLayout parent, TextView child, View dependency) {
    //告知監聽的dependency是Button
    return dependency instanceof Button;
  }

  @Override
  //當 dependency(Button)變化的時候,可以對child(TextView)進行操作
  public boolean onDependentViewChanged(CoordinatorLayout parent, TextView child, View dependency) {
    child.setX(dependency.getX()+200);
    child.setY(dependency.getY()+200);
    child.setText(dependency.getX()+","+dependency.getY());

    return true;
  }
}

注意兩個方法

layoutDependsOn() 代表尋找被觀察View

onDependentViewChanged() 被觀察View變化的時候回調用的方法

在onDependentViewChanged中,我們讓TextView跟隨Button的移動而移動。代碼比較簡單,一看就懂。

Tip

必須重寫帶雙參的構造器,因為從xml反射需要調用。

接下來,在xml中,給TextView設置我們的Behavior。

運行效果如下:

這裡寫圖片描述

這樣一個最簡單的behavior就做好了。

難度 2 仿UC折疊Behavior

這個效果布局嵌套比上一個例子些許復雜,如果看起來吃力,務必去補習CoordinatorLayout!!!!

先定義xml如下:



  

    

      

      <framelayout android:background="@color/primary" android:id="@+id/frameLayout" android:layout_gravity="bottom|center_horizontal" android:layout_height="100dp" android:layout_width="match_parent" android:orientation="vertical" app:layout_collapsemode="parallax" app:layout_collapseparallaxmultiplier="0.3">

      </framelayout>
    
  


  

    
  

  
  

  

  

有一點值得注意的是,app:layout_anchor=”@id/frameLayout”這個屬性,是附著的意思,這裡我用作給了toolbar,代表toolbar附著在了frameLayout之上。會跟隨frameLayout的scroll而變化Y的值。

思路分析

如何實現折疊呢,下半部分不用管了,AppBarLayout已經幫我們做好了,我們只要標注相應的scrollflags即可,所以,如上的布局,不做任何處理的話,作為標題的TextView是一直顯示的,於是只要讓TextView跟隨Toolbar變化而變化就可以了。 接下來就創建一個Behavior類!

public class DrawerBehavior extends CoordinatorLayout.Behavior {
  private int mFrameMaxHeight = 100;
  private int mStartY;
  @Override
  public boolean layoutDependsOn(CoordinatorLayout parent, TextView child, View dependency) {
    return dependency instanceof Toolbar;
  }

  public DrawerBehavior(Context context, AttributeSet attrs) {
    super(context, attrs);
  }

  @Override public boolean onDependentViewChanged(CoordinatorLayout parent, TextView child,
      View dependency) {

  }
}

現在你應該可以很輕易的看懂這個Behavior的結構了。我們主要大展身手的地方其實是在onDependentViewChanged方法。

@Override public boolean onDependentViewChanged(CoordinatorLayout parent, TextView child,
      View dependency) {
    //記錄開始的Y坐標  也就是toolbar起始Y坐標
    if(mStartY == 0) {
      mStartY = (int) dependency.getY();
    }

    //計算toolbar從開始移動到最後的百分比
    float percent = dependency.getY()/mStartY;

    //改變child的坐標(從消失,到可見)
    child.setY(child.getHeight()*(1-percent) - child.getHeight());
    return true;
  }

裡面監聽了Toolbar的Y坐標變化,然後讓TextView的Y坐標也跟著變化。達到如預覽圖效果。

這裡寫圖片描述

難度3 頭像縮放效果

相信有了以上兩個例子,這個效果對你來說不難了,不就是讓imageView監聽Toolbar然後跟隨Toolbar的唯一變化而進行位移以及縮放麼。

所以具體的解析就不說了,直接上個Behavior代碼

/泛型為child類型
public class CustomBehavior extends CoordinatorLayout.Behavior {
    private Context mContext;
    //頭像的最終大小
    private float mCustomFinalHeight;

    //最終頭像的Y
    private float mFinalAvatarY;

    private float mStartAvatarY;

    private float mStartAvatarX;

    private int mAvatarMaxHeight;

    private BounceInterpolator interpolator = new BounceInterpolator();

    public CustomBehavior(Context context, AttributeSet attrs) {
        mContext = context;
        if (attrs != null) {
            TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CustomBehavior);
            //獲取縮小以後的大小
            mCustomFinalHeight = a.getDimension(R.styleable.CustomBehavior_finalHeight, 0);
            a.recycle();
        }
    }




    // 如果dependency為Toolbar
    @Override
    public boolean layoutDependsOn(CoordinatorLayout parent, CircleImageView child, View dependency) {
        return dependency instanceof Toolbar;
    }


    //當dependency變化的時候調用
    @Override
    public boolean onDependentViewChanged(CoordinatorLayout parent, CircleImageView child, View dependency) {
        //初始化屬性
        //init(child, dependency);
        mFinalAvatarY = dependency.getHeight()/2;
        if(mStartAvatarY == 0){
            mStartAvatarY = dependency.getY();
        }
        if(mStartAvatarX == 0){
            mStartAvatarX = child.getX();
        }

        if(mAvatarMaxHeight == 0){
            mAvatarMaxHeight = child.getHeight();
        }


        //child.setY(dependency.getY());

        //讓ImageView跟隨toolbar垂直移動

        child.setY(dependency.getY()+dependency.getHeight()/2-mCustomFinalHeight/2);

        float percent = dependency.getY() / mStartAvatarY;

        //float x = mStartAvatarX*(1+percent);
        float x = mStartAvatarX * (1+ interpolator.getInterpolation(percent));

        //Log.e("wing","started x "+ mStartAvatarX + " currentX "+ x);

        //當toolbar 達到了位置,就不改變了。
        if(dependency.getY() > dependency.getHeight()/2) {
                child.setX(x);
        }else {
            child.setX(mStartAvatarX + ((mAvatarMaxHeight-mCustomFinalHeight))/2);
        }

        CoordinatorLayout.LayoutParams layoutParams =
            (CoordinatorLayout.LayoutParams) child.getLayoutParams();
        layoutParams.height = (int) ((mAvatarMaxHeight-mCustomFinalHeight) * percent + mCustomFinalHeight);
        layoutParams.width =  (int) ((mAvatarMaxHeight-mCustomFinalHeight) * percent + mCustomFinalHeight);
        child.setLayoutParams(layoutParams);

        return true;
    }


}

還是說說坐標計算相關的吧。舉個例子。如何讓ImageView處於Toolbar中心呢,我的代碼如下

 //讓ImageView跟隨toolbar垂直移動

        child.setY(dependency.getY()+dependency.getHeight()/2-mCustomFinalHeight/2);

為什麼是這樣? 上個圖就明白了

這裡寫圖片描述

怎麼樣,不難吧,哈 喜歡的點個贊 給個star哦~~

項目地址 https://github.com/githubwing/CustomBehavior

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved