behavior_behaviors - CSDN
精华内容
参与话题
  • 简介Behavior的中文翻译是”行为”的意思.Behavior是Android新出的Design库里新增的布局概念。Behavior只有是CoordinatorLayout的直接子View才有意义。可以为任何View添加一个Behavior。 Material Design里面的...

    一.简介

    Behavior的中文翻译是”行为”的意思.

    Behavior是Android新出的Design库里新增的布局概念。Behavior只有是CoordinatorLayout的直接子View才有意义。可以为任何View添加一个Behavior。

    Material Design里面的CoordinatorLayout是一个非常强大的控件,它接管了child组件之间的交互。让你滑动交互使用更加方便简单,效果也更加强大,不需要像以前那样自己处理一坨什么乱七八槽的滑动,事件传递之类的处理了。

    Behavior是一系列回调。让你有机会以非侵入的为View添加动态的依赖布局,和处理父布局(CoordinatorLayout)滑动手势的机会。如果我们想实现控件之间任意的交互效果,完全可以通过自定义 Behavior 的方式达到。

    在学习自定义behavior之前我们先看一看官方内置的behavior
    这里写图片描述

    二.BottomSheetBehavior

    BottomSheetBehavior实现的效果就是一个布局底部弹出,类似于饿了么查看购物车的效果,这种效果我们可以有很多种方式实现,使用BottomSheetBehavior你会发现简直只需要一行代码.

    这里写图片描述

    1.页面布局

    <?xml version="1.0" encoding="utf-8"?>
    <android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/activity_group_car_boottom_sheet"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context="com.testdemo.king.kingtestdemo.GroupCarBoottomSheetActivity">
    
    
        <LinearLayout
            android:visibility="visible"
            android:orientation="horizontal"
            android:layout_width="match_parent"
            android:layout_height="match_parent">
            <Button
                android:id="@+id/bt1"
                android:text="显示bottomsheetBehavior"
                android:layout_width="0dp"
                android:layout_weight="1"
                android:layout_height="wrap_content" />
            <Button
                android:id="@+id/bt2"
                android:text="显示bottomsheetBehaviorDialog"
                android:layout_width="0dp"
                android:layout_weight="1"
                android:layout_height="wrap_content" />
        </LinearLayout>
        <RelativeLayout
    
            android:id="@+id/design_bottom_sheet"
            android:layout_width="match_parent"
            android:layout_gravity="center"
            android:layout_height="match_parent"
            android:background="@color/colorAccent"
            app:behavior_hideable="true"
            app:behavior_peekHeight="100dp"
            app:elevation="4dp"
            app:layout_behavior="@string/bottom_sheet_behavior">
    
            <TextView
                android:id="@+id/bottomsheet_text"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:text="展示Bottom Sheets"
                android:textColor="#FFFFFF" />
    
        </RelativeLayout>
    
    
    </android.support.design.widget.CoordinatorLayout>
    

    属性说明

    //折叠的高度
    app:behavior_peekHeight="10dp"          setPeekHeight
    //是否可以隐藏
    app:behavior_hideable="true"            setHideable
    //是否跳过折叠状态
    app:behavior_skipCollapsed="true"       setSkipCollapsed

    2.代码实现

    只需要获取到这个behavior

            bottomSheetBehavior = BottomSheetBehavior.from((View)rlBottom);
    

    然后点击的时候按钮时候控制其隐藏和出现即可

    case R.id.bt1:
                    if (bottomSheetBehavior.getState() == BottomSheetBehavior.STATE_COLLAPSED) {
                        bottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN);
                    } else {
                        bottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
                    }
                    break;

    状态说明:

    • STATE_COLLAPSED: 关闭Bottom Sheets,显示peekHeight的高度,默认是0
    • STATE_DRAGGING: 用户拖拽Bottom Sheets时的状态
    • STATE_SETTLING: 当Bottom Sheets view释放时记录的状态。
    • STATE_EXPANDED: 当Bottom Sheets 展开的状态
    • STATE_HIDDEN: 当Bottom Sheets 隐藏的状态

    3.状态监听

    我们可以通过监听状态的改变做一些自定义的操作,比如这样.
    这里写图片描述

      bottomSheetBehavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
                @Override
                public void onStateChanged(@NonNull View bottomSheet, int newState) {
    //                /这里是bottomSheet 状态的改变,根据slideOffset可以做一些动画
                }
    
                @Override
                public void onSlide(@NonNull View bottomSheet, float slideOffset) {
                    //这里是拖拽中的回调,根据slideOffset可以做一些动画
                    Log.e("king",slideOffset+"");
                    if(slideOffset>0){
                        if(slideOffset>0.5)slideOffset=0.5f;
                        ViewGroup.LayoutParams para1;
                        para1 = bottomSheet.getLayoutParams();
                        para1.width = (int) (rlBottomWidth*(0.5+slideOffset));
                        bottomSheet.setLayoutParams(para1);
                    }
    
    
                }
            });

    三.BottomSheetDialog

    BottomSheetDialog是一个基于bottomSheetbehavior实现的dialog

    代码实现

     private void initBottomSheetDialog() {
            dialog = new BottomSheetDialog(this);
            View dialogView = LayoutInflater.from(this).inflate(R.layout.item_text, null, false);
            ((TextView) dialogView.findViewById(R.id.text)).setText("bottomsheetDialog");
            dialog.setContentView(dialogView);
            dialog.hide();
        }

    然后只需要调用dialog.hide();或者show()方法就能实现dialog的显示隐藏了.

    这里写图片描述

    当然,BottomSheetDialog也能调用状态监听,具体实现如下

    private void setBehaviorCallback() {
            View view = dialog.getDelegate().findViewById(android.support.design.R.id.design_bottom_sheet);
            final BottomSheetBehavior bottomSheetBehavior = BottomSheetBehavior.from(view);
            bottomSheetBehavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
                @Override
                public void onStateChanged(@NonNull View bottomSheet, int newState) {
                    if (newState == BottomSheetBehavior.STATE_HIDDEN) {
                        dialog.dismiss();
                        bottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
                    }
                }
    
                @Override
                public void onSlide(@NonNull View bottomSheet, float slideOffset) {
                }
            });
        }

    四.SwipeDismissBehavior

    SwipeDismissBehavior是一个实现侧滑删除的效果,比较简单

    private void initSwipeDismissBehavior() {
            SwipeDismissBehavior<View> swipe = new SwipeDismissBehavior();
            swipe.setSwipeDirection(SwipeDismissBehavior.SWIPE_DIRECTION_ANY);
    
            swipe.setListener(
                    new SwipeDismissBehavior.OnDismissListener() {
                        @Override
                        public void onDismiss(View view) {
    
                        }
    
                        @Override
                        public void onDragStateChanged(int state) {
                        }
                    });
    
            CoordinatorLayout.LayoutParams coordinatorParams =
                    (CoordinatorLayout.LayoutParams)tv1 .getLayoutParams();
    
            coordinatorParams.setBehavior(swipe);
        }

    五.AppBarLayout$ScrollingViewBehavior

    ScrollingViewBehavior的简单应用大家参考一下这篇文章吧
    http://blog.csdn.net/aqi00/article/details/56834285

    系统默认提供的behavior毕竟只能实现一部分功能,下一篇博客我们将介绍如何使用自定义behavior来实现复杂的功能.

    展开全文
  • Android Behavior

    千次阅读 2017-01-18 14:50:12
    Behavior是Android新出的Design库里新增的布局概念。Behavior只有是CoordinatorLayout的直接子View才有意义。可以为任何View添加一个BehaviorBehavior是一系列回调。让你有机会以非侵入的为View添加动态的依赖...

    原文出处:http://www.jianshu.com/p/a506ee4afecb


    Behavior是Android新出的Design库里新增的布局概念。Behavior只有是CoordinatorLayout的直接子View才有意义。可以为任何View添加一个Behavior。
    Behavior是一系列回调。让你有机会以非侵入的为View添加动态的依赖布局,和处理父布局(CoordinatorLayout)滑动手势的机会。不过官方只有少数几个Behavior的例子。对于理解Behavior实在不易。开发过程中也是很多坑,下面总结一下CoordinatorLayout与Behavior。

    依赖

    首先自定义一个Behavior。

        public class MyBehavior extends CoordinatorLayout.Behavior{
            public MyBehavior(Context context, AttributeSet attrs) {
                super(context, attrs);
            }
        }

    一定要重写这个构造函数。因为CoordinatorLayout源码中parseBehavior()函数中直接反射调用这个构造函数。

    static final Class<?>[] CONSTRUCTOR_PARAMS = new Class<?>[] {
            Context.class,
            AttributeSet.class
    };

    下面反射生成Behavior实例在实例化CoordinatorLayout.LayoutParams时:

    final Class<Behavior> clazz = (Class<Behavior>) Class.forName(fullName, true,
                     context.getClassLoader());
    c = clazz.getConstructor(CONSTRUCTOR_PARAMS);
    c.setAccessible(true);
    constructors.put(fullName, c);
    return c.newInstance(context, attrs)

    在任意View中添加:

    app:layout_behavior=“你的Behavior包含包名的类名”

    然后CoordinatorLayout就会反射生成你的Behavior。

    另外一种方法如果你的自定义View默认使用一个Behavior。
    在你的自定义View类上添加@DefaultBehavior(你的Behavior.class)这句注解。
    你的View就默认使用这个Behavior。就像AppBarLayout一样。

    @DefaultBehavior(AppBarLayout.Behavior.class)
    public class AppBarLayout extends LinearLayout {}

    生成Behavior后第一件事就是确定依赖关系。重写Behavior的这个方法来确定你依赖哪些View。

    @Override
    public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
        return dependency.getId() == R.id.first;
    }

    child 是指应用behavior的View ,dependency 担任触发behavior的角色,并与child进行互动。
    确定你是否依赖于这个View。CoordinatorLayout会将自己所有View遍历判断。
    如果确定依赖。这个方法很重要。当所依赖的View变动时会回调这个方法。

    @Override
    public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {
        return true;
    }

    下面这个例子:

        <declare-styleable name="Follow">
            <attr name="target" format="reference"/>
        </declare-styleable>

    先自定义target这个属性。

      public class FollowBehavior extends CoordinatorLayout.Behavior {
      private int targetId;
    
      public FollowBehavior(Context context, AttributeSet attrs) {
          super(context, attrs);
          TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Follow);
          for (int i = 0; i < a.getIndexCount(); i++) {
              int attr = a.getIndex(i);
              if(a.getIndex(i) == R.styleable.Follow_target){
                  targetId = a.getResourceId(attr, -1);
              }
          }
          a.recycle();
      }
    
      @Override
      public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {
           child.setY(dependency.getY()+dependency.getHeight());
          return true;
      }
    
      @Override
      public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
          return dependency.getId() == targetId;
      }
    }

    xml中:

    <android.support.design.widget.CoordinatorLayout    xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fitsSystemWindows="true"
        tools:context=".MainActivity">
    
        <View
            android:id="@+id/first"
            android:layout_width="match_parent"
            android:layout_height="128dp"
            android:background="@android:color/holo_blue_light"/>
    
        <View
            android:id="@+id/second"
            android:layout_width="match_parent"
            android:layout_height="128dp"
            app:layout_behavior=".FollowBehavior"
            app:target="@id/first"
            android:background="@android:color/holo_green_light"/>
    
    
    </android.support.design.widget.CoordinatorLayout>

    效果是不管first怎么移动。second都会在他下面。


    01.gif

    滑动

    Behavior最大的用处在于对滑动事件的处理。就像CollapsingToolbarLayout的那个酷炫效果一样。

    主要是这3个方法,所依赖对象的滑动事件都将通知进来:

    @Override
    public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, View child, View directTargetChild, View target, int nestedScrollAxes) {
        return true;//这里返回true,才会接受到后续滑动事件。
    }
    
    @Override
    public void onNestedScroll(CoordinatorLayout coordinatorLayout, View child, View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
    //进行滑动事件处理
    }
    
    @Override
    public boolean onNestedFling(CoordinatorLayout coordinatorLayout, View child, View target, float velocityX, float velocityY, boolean consumed) {
    //当进行快速滑动
        return super.onNestedFling(coordinatorLayout, child, target, velocityX, velocityY, consumed);
    }

    注意被依赖的View只有实现了NestedScrollingChild接口的才可以将事件传递给CoordinatorLayout。
    但注意这个滑动事件是对于CoordinatorLayout的。所以只要CoordinatorLayout有NestedScrollingChild就会滑动,他滑动就会触发这几个回调。无论你是否依赖了那个View。
    下面就是一个简单的View跟随ScrollView滑入滑出屏幕的例子。可以是Toolbar或其他任何View。

    public class ScrollToTopBehavior extends CoordinatorLayout.Behavior<View>{
        int offsetTotal = 0;
        boolean scrolling = false;
    
        public ScrollToTopBehavior(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        @Override
        public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, View child, View directTargetChild, View target, int nestedScrollAxes) {
            return true;
        }
    
        @Override
        public void onNestedScroll(CoordinatorLayout coordinatorLayout, View child, View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
            offset(child, dyConsumed);
        }
    
        public void offset(View child,int dy){
            int old = offsetTotal;
            int top = offsetTotal - dy;
            top = Math.max(top, -child.getHeight());
            top = Math.min(top, 0);
            offsetTotal = top;
            if (old == offsetTotal){
                scrolling = false;
                return;
            }
            int delta = offsetTotal-old;
            child.offsetTopAndBottom(delta);
            scrolling = true;
        }
    
    }

    xml中:

    <android.support.design.widget.CoordinatorLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fitsSystemWindows="false"
        tools:context=".MainActivity">
    
        <android.support.v4.widget.NestedScrollView
            android:id="@+id/second"
            android:layout_width="match_parent"
            android:layout_height="match_parent">
    
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content">
                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="128dp"
                    style="@style/TextAppearance.AppCompat.Display3"
                    android:text="A\nB\nC\nD\nE\nF\nG\nH\nI\nJ\nK\nL\nM\nN\nO\nP\nQ\nR\nS\nT\nU\nV\nW\nX\nY\nZ"
                    android:background="@android:color/holo_red_light"/>
            </LinearLayout>
        </android.support.v4.widget.NestedScrollView>
    
        <View
            android:id="@+id/first"
            android:layout_width="match_parent"
            android:layout_height="128dp"
            app:layout_behavior=".ScrollToTopBehavior"
            android:background="@android:color/holo_blue_light"/>
    
    </android.support.design.widget.CoordinatorLayout>

    当NestedScrollView滑动的时候,first也能跟着滑动。toolbar和fab的上滑隐藏都可以这样实现。


    02.gif

    事件处理

    这2个回调与View中的事件分发是一样的。所有Behavior能在子View之前收到CoordinatorLayout的所有触摸事件。可以进行拦截,如果拦截事件将不会流经子View。因为这2个方法都是在CoordinatorLayout的 回调中

    @Override
    public boolean onInterceptTouchEvent(CoordinatorLayout parent, View child, MotionEvent ev) {
        return super.onInterceptTouchEvent(parent, child, ev);
    }
    
    @Override
    public boolean onTouchEvent(CoordinatorLayout parent, View child, MotionEvent ev) {
        return super.onTouchEvent(parent, child, ev);
    }

    AppBarLayout的收缩原理分析

    示例中给可滑动View设的Behavior是
    @string/appbar_scrolling_view_behavior(android.support.design.widget.AppBarLayout$ScrollingViewBehavior)。
    ScrollingViewBehavior的源码不多,看得出唯一的作用是把自己放到AppBarLayout的下面...(不能理解为什么叫ScrollingViewBehavior
    所有View都能使用这个Behavior。

    AppBarLayout自带一个Behivior。直接在源码里注解声明的。这个Behivior也只能用于AppBarLayout。
    作用是让他根据CoordinatorLayout上的滚动手势进行一些效果(比如收缩)。与ScrollingViewBehavior是无关的,加不加ScrollingViewBehavior不影响收缩。
    只不过只有某些可滑动View才会把滑动事件响应给CoordinatorLayout才能继而响应给AppBarLayout。

    展开全文
  • Android Behavior之相关解析

    千次阅读 2017-10-25 17:33:18
    第一个简单的自定义Behavior在Android 5.0 的时候推出了CoordinatorLayout控件,该控件从翻译上来说称之为 协调性布局,我的理解是,对于他下面的子控件的布局,大小,滚动等等一系列的东西,由每一个子控

    如果不了解Android嵌套滚动,最好看一下我之前的文章 Android 嵌套滑动——NestedScrolling完全解析,当然不了解对本篇文章的阅读也不会有太大的阻塞。

    第一个简单的自定义Behavior

    在Android 5.0 的时候推出了CoordinatorLayout控件,该控件从翻译上来说称之为 协调性布局,我的理解是,对于他下面的子控件的布局,大小,滚动等等一系列的东西,由每一个子控件商量沟通着来,及每一个控件对于测量,布局等都有发言权,不在是由类似与线性布局一样,你必须垂直着排放,某某必须在下面。那么如何实现每个子控件都有发言权呢,便是通过一个叫behavior的来进行操作。每一个子控件都可以指定一个behavior,该behavior中会包含一些CoordinatorLayoutmeaseure layout时的回调方法,这样我们可以根据每个控件的不同来进行实现,这样就达到了布局和测量交个子控件自己来做。

    首先看一下我们利用behavior所实现的一个简单效果。

    这里写图片描述

    有两个小方块,垂直居中排列,下面的小方块会跟随上面的小方块一起滑动。

    该效果可以有多种方式的实现,但为了表述behavior的原理,实现方式可能会稍显复杂。但目的是为了更好的学习behavior

    实现分析

    因为我们要学习使用behavior,那么肯定跟布局要使用CoordinatorLayout,他仅支持layout_gravity而不支持线性布局的垂直等排列,所以第一个问题便是怎么让下面的小方块放到合适的位置。

    其次,上面方块需要能够消耗手指触摸以让自身根据手指的滑动而移动。

    最后,便是使下面的方块监听上面方块的移动,以达到跟随上面方块的移动。

    根据实现分析,我们来实现代码。

    代码实现

    首先布局文件activity_behavior.xml

    <?xml version="1.0" encoding="utf-8"?>
    <android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <View
            android:id="@+id/header"
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:layout_gravity="center_horizontal"
            android:layout_marginTop="50dp"
            android:background="#ff00ff"
            app:layout_behavior=".behavior.HeaderBehavior" />
        <View
            android:id="@+id/bottom"
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:layout_gravity="center_horizontal"
            android:layout_marginTop="50dp"
            android:background="#33f0ff"
            app:layout_behavior=".behavior.BottomBehavior" />
    </android.support.design.widget.CoordinatorLayout>

    该布局文件中主要定义了两个带有颜色的小方块,其中需要关注三个点:

    • 上面小方块定义了id为header,注意此id在后面会用到,因为我们下面的小方块是通过第一个方块来定位的。
    • 下面小方块中有一个layout_marginTop属性,如果我们不做任何操作,那么该小方块会和第一个小方块重合,我们需要的是该margin 是基于第一个小方块的,类似于垂直线性布局的margin。
    • 这两个子控件都分别添加了layout_behavior属性,该属性的值便是我们自定义的Behvior,注意代码中省略了包名(类似于activity的注册时可以省略包名一样)。

    因为我们所有的操作都是在behavor中完成的,所以不在叙述Activity的代码。

    从布局中我们可以看到定义了两个behavior,分别是HeaderBehaviorBottomBehavior方法,根据之前的实现分析,他们的分工如下:

    • HeaderBehavior:实现第一个小方块消耗手指触摸事件,让自己跟随手指移动。
    • BottomBehavior:根据第一个小方块的位置,定位自己的位置,在第一个小方块之下;监听第一个小方块,跟随第一个小方块移动。

    基于此,我们看一下HeaderBehavior:

    
    public class HeaderBehavior extends CoordinatorLayout.Behavior<View> {
        // 记录手指触摸的位置
        private int mLastY = 0;
    
        public HeaderBehavior(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        @Override
        public boolean onTouchEvent(CoordinatorLayout parent, View child, MotionEvent ev) {
            // 手指触摸的回调
            switch (ev.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    mLastY = (int) ev.getRawY();
                    break;
                case MotionEvent.ACTION_MOVE:
                    int y = (int) ev.getRawY();
                    child.setTranslationY(child.getTranslationY() + y - mLastY);
                    mLastY = y;
                    break;
            }
            return true;
        }
    }

    首先,该类继承CoordinatorLayout.Behavior并且声明了一个泛型,该泛型主要约束当前behavior可以声明到哪些控件上。如果定义的是RelativeLayout,则只能声明到RelativeLayout上。

    在之前说过,Behavior中会包含一些测量,事件触摸的回调,而onTouchEvent便是其中的一个回调。他会将CoordinatorLayoutonTouchEvent()回调到该方法。当前方法返回true,那么CoordinatorLayoutonTouchEvent()也会返回true

    具体的代码不在分析,就是根据手指移动,对当前控件进行偏移。

    在这里如果对事件分发不是太熟悉的可能会有一个混淆,认为该onTouchEvent()是子控件的onTouchEvent()的回调。这是错误的。

    因为behavior中的所有回调是来自与CoordinatorLayout.Behavior中的相关方法的回调,与子控件无关

    对于BottomBehavior,需要完成两件事情,但这两件事情都需要依赖第一个小方块,那么怎么定义依赖呢?

    Behavior中有一个重载方法layoutDependsOn(),该方法能够实现我们对第一个小方块的依赖。

    看一下BottomBehavior的代码

    public class BottomBehavior extends CoordinatorLayout.Behavior<View> {
        public BottomBehavior(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
        // =============== 根本:添加依赖 =============================
        @Override
        public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
            return dependency.getId() == R.id.header;
        }
    
        // ================ 第一部分:定位 ========================
        @Override
        public boolean onLayoutChild(CoordinatorLayout parent, View child, int layoutDirection) {
            // getDependencies  获取child 依赖的view
            List<View> dependencies = parent.getDependencies(child);
    //        parent.getDependents(child)  // 获取依赖child 的控件
            View header = findFirstDependency(dependencies);
            if (header != null) {
                CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams) child.getLayoutParams();
                Rect available = new Rect();
                available.set(parent.getPaddingLeft() + lp.leftMargin,
                        header.getBottom() + lp.topMargin,
                        parent.getWidth() - parent.getPaddingRight() - lp.rightMargin,
                        parent.getHeight() - parent.getPaddingBottom() - lp.bottomMargin);
                final Rect out = new Rect();
                GravityCompat.apply(resolveGravity(getFinalGravity(lp.gravity)), child.getMeasuredWidth(),
                        child.getMeasuredHeight(), available, out, layoutDirection);
                child.layout(out.left, out.top, out.right, out.bottom);
            } else {
                super.onLayoutChild(parent, child, layoutDirection);
            }
            return true;
        }
    
        public int getFinalGravity(int gravity) {
            // 获取当前控件的`layout_gravity`属性
            if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == 0) {
                gravity = gravity | Gravity.TOP;
            }
            if ((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) == 0) {
                gravity = gravity | Gravity.LEFT;
            }
            return gravity;
        }
    
        private static int resolveGravity(int gravity) {
            return gravity == Gravity.NO_GRAVITY ? GravityCompat.START | Gravity.TOP : gravity;
        }
    
        private View findFirstDependency(List<View> views) {
            // 查找最根本的依赖
            for (View view : views) {
                if (view.getId() == R.id.header) {
                    return view;
                }
            }
            return null;
        }
        // ================ 第二部分:监听移动 ========================
        @Override
        public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {
            child.setTranslationY(dependency.getTranslationY());
            return true;
        }
    }
    

    根据功能,分为了三个部分,首先通过layoutDependsOn方法定义依赖,返回true表示需要依赖,从该方法可以看出对于一个控件可以添加对个依赖。

    其次,对子控件进行定位,重写onLayoutChild()方法,该方法回调CoordinatorLayoutonLayout,在这里我们可以对子控进行定位。

    通过parent.getDependencies(child)获取到当前子控件所依赖的所有控件,然后通过findFirstDependency()找到我们定位所用到的headerView,最后根据headerView的位置计算剩余可用的空间进行定位,调用立刻child.layout()确定最终的位置。

    最后便是监听第一个小方块的移动,因为我们通过layoutDependsOn添加了依赖,那么我们可以重载onDependentViewChanged()方法,该方法在关心的控件位置和大小发生变化时会回调。

    总结

    整个流程下来,总的来说就是定义Behavior,在Behavior的重载方法中完成对子控件的measure layout 事件处理等等。

    最后强调一下 behavior中的所有回调是来自与CoordinatorLayout.Behavior中的相关方法的回调,与子控件无关

    Behavior中相关重载方法分析

    在上一个例子中,我们了解到behavior的关键便是重载一些方法,那么都是有那些方法可以重载呢,我们往下看:

    下面的方法都是我们自定义behavior中的方法,注意的是该方法是由CoordinatorLayout的相关方法中调用得以接到回调。

    public void onAttachedToLayoutParams(@NonNull CoordinatorLayout.LayoutParams params)

    调用时机: 当这个behavior被加入到LayoutParams中时,实际是指LayoutParams被创建时回调。

    public void onDetachedFromLayoutParams()

    behaviorLayoutParams中移除时回调,当ViewCoordinatorLayout中移除时不会被回调。

    public boolean onInterceptTouchEvent(CoordinatorLayout parent, V child, MotionEvent ev)

    CoordinatiorLayoutonInterceptTouchEvent()中,会回调该方法。

    其回调时机比较复杂,具体逻辑如下:

    • 遍历所有的behavior, 按照顺序执行onInterceptTouchEvent()
    • 如果其中一个behhavioronInterceptTouchEvent()返回true
      • 如果当前事件是ACTION_DOWN:则后面的behavioronIntercepTouchEvent()就不会被回调
      • 如果当前事件是其他事件,则后面会被收到一个ACTION_CANCEL 事件

    CoordinatiorLayoutonInterceptTouchEvent()中,如果有某一个Behavior返回true,则会保存该对象,以便onTouchEvent()时使用。

    如果该方法返回true,则CoordinatiorLayoutonInterceptTouchEvent()方法也会返回true;

    public boolean onTouchEvent(CoordinatorLayout parent, V child, MotionEvent ev)

    CoordinatiorLayoutonTouchEvent()中,会回调该方法。

    • 如果在onInterceptTouchEvent()时,某一个behavior返回了true,则会直接调用它的onTouchEvent()方法。
    • 如果不符合上面的条件,他会走和onInterceptTouchEvent()时的类似逻辑
      • Down事件时,在某一个behavioronTouchEvent()返回true之前的behavior都会被调用,之后的不会调用。
      • 其他事件,在某一个behavioronTouchEvent()返回true之前的behavior都会被调用,之后的会受到一个CANCEL事件。

    注意,如果再onInterceptTouchEvent()时没有找到一个处理的Behavior对象,会在onTouchEvent时遍历所有behavior,一旦找到一个behavior处理,则不会再一次遍历所有,而是使用保存的behavior对象。

    public boolean blocksInteractionBelow(CoordinatorLayout parent, V child)

    返回当前控件是否拦截触摸事件,因为触摸事件一般是按照子view自向往上进行便利,如果该方法返回了true,则会拦截触摸事件往下的传递,默认返回为false。其内部默认的实现如下:

     public boolean blocksInteractionBelow(CoordinatorLayout parent, V child) {
                return getScrimOpacity(parent, child) > 0.f;
            }

    可见其一般是通过getScrimOpacity()来判断的

    public float getScrimOpacity(CoordinatorLayout parent, V child)

    该方法限定返回值[0.0 ,1.0],如果大于0,则上面那个方法返回true ,则会拦截事件。同时该方法的返回会决定一个透明度。因为如果事件无法向下传递,会在CoordinatorLayout中画一个蒙层,优先于该View的在蒙层的上方,无法处理触摸的在蒙层的下方

    public int getScrimColor(CoordinatorLayout parent, V child)

    拦截事件后蒙层的颜色,默认是黑色。

    public boolean layoutDependsOn(CoordinatorLayout parent, V child, View dependency)

    决定该View依赖的其他View,如果返回true,表示child关心dependency的变化,具体那些变化,会在下面的一些回调方法中展示

    public boolean onDependentViewChanged(CoordinatorLayout parent, V child, View dependency)

    View关心的dependency发生size或者position的变化时,会回调该方法,如果该方法内也修改了viewposition或者size,则该方法应该返回true

    public void onDependentViewRemoved(CoordinatorLayout parent, V child, View dependency)

    关心的ViewCoordinatorLayout中移除时的回调通知

    public boolean onMeasureChild(CoordinatorLayout parent, V child,int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec, int heightUsed)

    measure时的回调,该方法如果返回true,则不会在走默认的子类测量流程。

    public boolean onLayoutChild(CoordinatorLayout parent, V child, int layoutDirection)

    onLayout()时的回调,如果返回true,则view的具体位置由该方法来定位。

    public static void setTag(View child, Object tag)
    public static Object getTag(View child)

    对指定的child设置和获取标签。

    public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, V child, View directTargetChild, View target, int nestedScrollAxes)

    该嵌套滚动和事件分发不同,每一个behavior的该方法都会被回调。只要有一个返回true,则CoordinatorLayout也会返回true。

    public void onNestedScrollAccepted(CoordinatorLayout coordinatorLayout, V child, View directTargetChild, View target, int nestedScrollAxes)
    上一个方法返回true ,则该方法就会被调用

    public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, V child, View target)

    停止嵌套滚动时的回调,每一个behavior都会被调用

    public void onNestedScroll(CoordinatorLayout coordinatorLayout, V child, View target,int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed)

    嵌套滚动相关,每一个behavior都会被调用

    public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, V child, View target, int dx, int dy, int[] consumed)

    嵌套滚动相关,每一个behavior都会被调用,但是因为其在嵌套滚动之前调用,则会计算每一个behavior中的消耗,获取最大的消耗往下传。

    public boolean onNestedFling(CoordinatorLayout coordinatorLayout, V child, View target,float velocityX, float velocityY, boolean consumed)

    嵌套滚动相关,每一个behavior都会被调用

    public boolean onNestedPreFling(CoordinatorLayout coordinatorLayout, V child, View target,float velocityX, float velocityY)

    嵌套滚动相关,每一个behavior都会被调用

    public void onRestoreInstanceState(CoordinatorLayout parent, V child, Parcelable state)
    public Parcelable onSaveInstanceState(CoordinatorLayout parent, V child)

    数据的保存和恢复相关。

    public WindowInsetsCompat onApplyWindowInsets(CoordinatorLayout coordinatorLayout, V child, WindowInsetsCompat insets)
    public boolean onRequestChildRectangleOnScreen(CoordinatorLayout coordinatorLayout, V child, Rect rectangle, boolean immediate)
    public boolean getInsetDodgeRect(@NonNull CoordinatorLayout parent, @NonNull V child,@NonNull Rect rect)

    暂时不知道是什么意思。。

    关于CoordinatorLayout中触摸分发事件onInterceptTouchEvent()onTouchEvent()的相关源码分析

    从之前的介绍中,了解到我们可以在Behavior中重载onTouchEvent()onInterceptTouchEvent()方法用以获取CoordinatorLayout的事件处理,那么对于多个behavior的触摸事件监听,具体回调流程是怎么样呢,下面我们就开始走进科学~

    首先看一下CoordinatorLayoutonInterceptTouchEvent()方法源码:

    
       @Override
        public boolean onInterceptTouchEvent(MotionEvent ev) {
            MotionEvent cancelEvent = null;
    
            final int action = MotionEventCompat.getActionMasked(ev);
    
            // Make sure we reset in case we had missed a previous important event.
            if (action == MotionEvent.ACTION_DOWN) {
                // 重置behavior的状态,主要是将behavior拦截事件置为true
                resetTouchBehaviors();
            }
    
            // 遍历所有的behavior ,获取事件处理状态
            final boolean intercepted = performIntercept(ev, TYPE_ON_INTERCEPT);
    
            if (cancelEvent != null) {
                // 搞不懂。。。
                cancelEvent.recycle();
            }
    
            if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
                // 事件结束,重置behavior 的状态
                resetTouchBehaviors();
            }
            return intercepted;
        }

    在开始的时候会重置一下Behavior的状态,这个状态主要指的是block,在前面behavior的方法列举中,可以看到blocksInteractionBelow()方法,该方法会返回是否拦截后面控件的事件,在这里,会先重置一下,默认为不拦截。

    然后通过performIntercept(ev, TYPE_ON_INTERCEPT)方法来遍历所有的behavior获取处理状态,最后返回。

    看一下performIntercept()的源码:

     private boolean performIntercept(MotionEvent ev, final int type) {
            boolean intercepted = false;
            boolean newBlock = false;
            MotionEvent cancelEvent = null;
            final int action = MotionEventCompat.getActionMasked(ev);
            // 获取所有的View ,该View 的顺序在不改变绘图优先级时,默认是所有子控件的倒序,及自下往上
            final List<View> topmostChildList = mTempList1;
            getTopSortedChildren(topmostChildList);
            final int childCount = topmostChildList.size();
            // 遍历所有的View ,对包含`behavior`的进行处理回调
            for (int i = 0; i < childCount; i++) {
                final View child = topmostChildList.get(i);
                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
                final Behavior b = lp.getBehavior();
                // Down事件,则不会走此逻辑,对于Move事件,如果intercepted 或 newBlock为true,则会回调一个ACTION_CANCEL
                if ((intercepted || newBlock) && action != MotionEvent.ACTION_DOWN) {
                    // Cancel all behaviors beneath the one that intercepted.
                    // If the event is "down" then we don't have anything to cancel yet.
                    if (b != null) {
                        if (cancelEvent == null) {
                            final long now = SystemClock.uptimeMillis();
                            cancelEvent = MotionEvent.obtain(now, now,
                                    MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0);
                        }
                        switch (type) {
                            case TYPE_ON_INTERCEPT:
                                b.onInterceptTouchEvent(this, child, cancelEvent);
                                break;
                            case TYPE_ON_TOUCH:
                                b.onTouchEvent(this, child, cancelEvent);
                                break;
                        }
                    }
                    continue;
                }
                // 关键方法,找到处理的behavior ,并处理,一旦某个behavior的方法返回true ,则后面的都不会在执行此逻辑
                if (!intercepted && b != null) {
                    switch (type) {
                        case TYPE_ON_INTERCEPT:
                            intercepted = b.onInterceptTouchEvent(this, child, ev);
                            break;
                        case TYPE_ON_TOUCH:
                            intercepted = b.onTouchEvent(this, child, ev);
                            break;
                    }
                    // 保存处理的behavior对象
                    if (intercepted) {
                        mBehaviorTouchView = child;
                    }
                }
    
                // 在onInterceptTouchEvent 中 DOWN事件,会重置所有的behavior的状态,该返回字段为false;
                // 所以对于DOWN事件,肯定不会走下面的break;提前结束循环
                // 而对于其他事件,如果wasBlocking 返回true ,则肯定会走入下面的break逻辑,提前跳出。及后面的behavior不会在回调,类似于拦截。
                final boolean wasBlocking = lp.didBlockInteraction();
                //如果wasBlocking为false , 该方法会调用每一个的behavior的blocksInteractionBelow()判断是否拦截向后面behavior的遍历,并将值赋值给didBlockInteraction();
                final boolean isBlocking = lp.isBlockingInteractionBelow(this, child);
                newBlock = isBlocking && !wasBlocking;
                if (isBlocking && !newBlock) {
                    // isBlock == true   wasBlock = true 走入逻辑,
                    break;
                }
            }
            topmostChildList.clear();
            return intercepted;
        }
    

    该方法中区分onTouchEvent()onInterceptTouchEvent(),可见他们的遍历逻辑几乎一致。

    代码注释上可以仔细撸一撸,到这里我们可以总结一下onInterceptTouchEvent()的执行逻辑,

    对于每一个behavioronInterceptTouchEvent()方法,会先按照CoordinatorLayout布局中自下往上(可能有特殊情况,改变绘制优先级时)进行遍历:

    如果是DOWN事件,会遍历到直到某一个behavioronInterceptTouchEvent()返回true为止,后面的不会在调用。在Down事件时,会找出在哪一个behavior会强制拦截所有事件。通过behaviorblocksInteractionBelow()作为依据。

    如果是除了DOWN事件,如果有强制拦截事件,则首先强制拦截事件的子控件之后的控件不会被回调。然后,依然从开始遍历,遍历到强制拦截事件的子控件结束为止,如果其中一个返回了true,则后面的会收到一个CANCEL事件。

    onInterceptTouchEvent()执行逻辑中,如果找到某个behavior处理事件,即返回true,则会保存该对象,以便onTouchEvent()中使用。

    那么在看一下CoordinatorLayoutonTouchEvent()源码

    
    @Override
        public boolean onTouchEvent(MotionEvent ev) {
            boolean handled = false;
            boolean cancelSuper = false;
            MotionEvent cancelEvent = null;
            final int action = MotionEventCompat.getActionMasked(ev);
            // 如果onInterceptTouchEvent()中找到了一个behvior中处理事件,则直接使用,否则调用performIntercept()查找处理的behavior
            if (mBehaviorTouchView != null || (cancelSuper = performIntercept(ev, TYPE_ON_TOUCH))) {
                final LayoutParams lp = (LayoutParams) mBehaviorTouchView.getLayoutParams();
                final Behavior b = lp.getBehavior();
                if (b != null) {
                    // 回调事件
                    handled = b.onTouchEvent(this, mBehaviorTouchView, ev);
                }
            }
    
            // 如果没有behavior 处理,则会调用基类的onTouchEvent()
            if (mBehaviorTouchView == null) {
                handled |= super.onTouchEvent(ev);
            } else if (cancelSuper) {
                // 在Down 的时候没有处理,在Move的时候处理,则需要取消之前的调用
                if (cancelEvent == null) {
                    final long now = SystemClock.uptimeMillis();
                    cancelEvent = MotionEvent.obtain(now, now,
                            MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0);
                }
                // 取消当前控件的事件处理,因为有某一个behavior处理了事件
                super.onTouchEvent(cancelEvent);
            }
    
            if (!handled && action == MotionEvent.ACTION_DOWN) {
    
            }
    
            if (cancelEvent != null) {
                cancelEvent.recycle();
            }
    
            if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
                resetTouchBehaviors();
            }
    
            return handled;
        }

    注意:在onTouchEvent()中没有重置behavior的状态。及拦截所有事件的状态。

    开始的时候,如果onInterceptTouchEvent()中找到了处理的mBehaviorTouchView,则直接调用对应behavioronTouchEvent()方法,其他的不会调用。如果该behavior返回false,则CoordinatorLayoutonTouchEvent()也返回false

    如果没有找到,则会调用performIntercept()找到要处理的behavior,此时会回调behavioronTouchEvent()方法。如果依然没有处理,则会调用基类的super.onTouchEvent()处理事件,如果有事件处理,则会给积累发送一个取消事件。

    至于他的遍历逻辑,及performIntercept()中的逻辑和onInterceptTouchEvent()时的几乎一致。

    总结

    基本:所有的遍历都是从CoordinatorLayout中子控件倒序开始遍历的(改变绘制流程除外)

    onInterceptTouchEvent()调用逻辑:

    • 对于Down事件:会回调从第一个开始知道某一个的behavioronInterceptTouchEvent()返回true。

    • 对于除了Down以外的事件:如果behaviorblocksInteractionBelow()返回true ,则会拦截所有事件。即只遍历从第一个到该behavior,在遍历过程中的某一个behavioronInterceptTouchEvent()返回true,则其之前的正常回调,其之后的会获得一个CANCEL事件。

    onTouchEvent()调用逻辑

    • 如果onInterceptTouchEvent()中找到了behavior,及某个behavior onInterceptTouchEvent()返回了true。则逻辑如下:

      • 直接调用该behavioronTouchEvent()方法,如果该方法返回false,则调用基类的super.onTouchEvent()
    • 如果onInterceptTouchEvent()没有找到,则会进行遍历,遍历范围为从第一个到某个behaviorblocksInteractionBelow()返回true为止。如果找到了,会保存,不会在遍历。

      • DOWN事件: 会回调从第一个开始知道某一个的behavioronTouchEvent()返回true。

      • 其他事件:即只遍历从第一个到该behavior,在遍历过程中的某一个behavioronTouchEvent()返回true,则其之前的正常回调,其之后的会获得一个CANCEL事件。

      • 注意,该遍历如果找到处理的了,无论是Down或者其他事件,则不会在遍历,只会使用找到的behavior,如果没找到,则其他事件时,会再次遍历。
    展开全文
  • 在进行CSS网页布局的时候,我们经遇到刷新要保留表单里内容的时候,习惯的做法使用cookie,但是那样做实在是很麻烦,css中的behavior就为我们很好的解决了这个问题。 behavior的语法: ww.52cssbehavior :...

    在进行CSS网页布局的时候,我们经遇到刷新要保留表单里内容的时候,习惯的做法使用cookie,但是那样做实在是很麻烦,css中的behavior就为我们很好的解决了这个问题。

    behavior的语法:

    ww.52cssbehavior : url ( url ) | url ( #objID ) | url ( #default#behaviorName )
      取值:
      url ( url ) : 使用绝对或相对 url 地址指定DHTML行为组件(.htc)
      url ( #objID ) : 使用二进制实现(作为 ActiveX® 控件)的行为。此处的 #objID 为 object 对象的 id 属性值
      url ( #default#behaviorName ) : IE的默认行为。由行为的名称标识( #behaviorName )指定
      说明:设置或检索对象的DHTML行为。多个行为之间用空格隔开。

      当多个附加到同一要素的行为发生冲突时,其结果取决于行为应用于要素的顺序。后一个行为的优先权高于前一个行为。同样的规则适用于不同行为提供的属性、事件、方法所发生的名称冲突。
      可以使用 addBehavior 方法动态的将行为附着到对象。
      此属性对于 currentStyle 对象而言是只读的。对于其他对象而言是可读写的。
      务必注意使用样式表(CSS)的 behavior 属性内联定义或使用 addBehavior 方法附着的行为不会在对象从文档树中移除时被自动分离。而在文档中的样式表规则定义的行为会在对象从文档树中移除时被自动分离。
      对应的脚本特性为 behavior 。 

      示例: [ww.52css.com]
    p { behavior: url(#default#download); }
    div { behavior: url(fly.htc) url(shy.htc); }
    div { behavior: url(#myObject); }

      应用1:刷新也保留输入框里面的文字
    www.52css.com]
      .sHistory {}{behavior:url(#default#savehistory);}

      应用2:调用脚本
    w.52css.com]
        <html>
        <head>
          <style>
          h1 { behavior: url(behave.htc) }
          </style>
        </head>
        <body>
          <h1>把鼠标放在这里 </h1>
        </body>
        </html>
        behave.htc

        <component>
        <attach for="element" event="onmouseover" handler="hig_lite" />
        <attach for="element" event="onmouseout" handler="low_lite" />
        <script type="text/javascript">
        function hig_lite()
        {
          element.style.color=255
        }
        function low_lite()
        {
          element.style.color=0
        }
        </script>
        </component>
      
    注意:CSS 时尽量避免使用Behaviors技术

      Internet Explorer Behaviors
      它是什么?Internet Explorer 5 引入了行为 (behaviors)。behaviors 是一种通过使用 CSS 向 HTML 元素添加行为的方法。
      为什么要避免它?只有 Internet Explorer 支持 behavior 属性。
      用什么代替?请使用 JavaScript 和 HTML DOM 取而代之
    展开全文
  • 1.行为树基础 行为树中常用的有三类,分别是decorator、sequence和selector。decorator下只执行一个节点,sequence下会按照从左到右的顺序执行多个节点,selector是从多个节点中选择一个执行。 ...
  • Behavior Designer 中文版教程

    千次阅读 2017-08-14 08:52:42
    Behavior Designer 概述 Behavior Designer 是一个行为树插件!是为了让设计师,程序员,美术人员方便使用的可视化编辑器!Behavior Designer 提供了强大的 API 可以让你轻松的创建 tasks(任务),配合 uScript 和 ...
  • Yii2基本概念之——行为(Behavior)

    千次阅读 2018-03-02 23:25:17
    使用行为(behavior)可以在不修改现有类的情况下,对类的功能进行扩充。通过将行为绑定到一个类,可以使得类具有行为本身所具有的属性和方法,就好像是类本来就具有的这些属性和功能一样。 好的代码设计,必须要同时...
  • 自定义Behavior

    2018-03-23 18:14:11
    Behavior简介CoordinatorLayout是个很牛的布局容器,使用它可以很方面的实现很多效果,比如支付宝首页的折叠效果,知乎首页等等,Behavior是它的一个内部抽象类,声明Behavior属性的View可以和他它依赖的兄弟元素...
  • UE4简单巡逻BehaviorTree的构建

    千次阅读 2015-11-23 15:05:29
    上次我们搞了一个C++的AI代码初始化,但是只有C++初始化,AI是不会行动的。这次我们接着初始化之后的步骤,搞一个可以简单巡逻并且发现玩家之后会追踪的简单AI逻辑。 主要逻辑如下: 1.平时按照固定路线巡逻 ...
  • UE4学习笔记:行为树(BehaviorTree)实例

    千次阅读 2019-08-27 09:48:45
    下面用行为树创建一个简单的AI角色,没有玩家靠近时随机巡逻,当有玩家角色靠近时跑到玩家附近,...https://docs.unrealengine.com/zh-CN/Engine/ArtificialIntelligence/BehaviorTrees/BehaviorTreeQuickStart/i...
  • Behavior Designer is a behaviour tree implementation designed for everyone - programmers, artists, designers. Behavior Designer offers a powerful API allowing you to easily create new tasks. It also ...
  • Behavior Designer 中文(教程、手册、经验总结) 来源于网络的资源,整理发出。不是插件本体 Unity3D上,实现简单AI最好的工具,莫过于Behavior Designer了。也是本篇文章要和大家介绍的重点,毕竟Behavior ...
  • Behavior Designer is dedicated to behavior trees, which means that each update will be a better behavior tree implementation. Features: - An intuitive visual editor - A powerful API - Visual ...
  • 本文和大家重点讨论一下CSS中behavior属性语法的使用,在进行CSS网页布局的时候,我们经遇到刷新要保留表单里内容的时候,习惯的做法使用cookie,但是那样做实在是很麻烦,CSS中的behavior就为我们很好的解决了这个...
  • Material Design系列,自定义Behavior实现Android知乎首页

    万次阅读 多人点赞 2016-08-14 18:59:33
    Material Design系列,自定义自定义Behavior实现Android知乎首页,用Behavior实现知乎首页上滑或者下滑时FAB和TAB导航的显示和隐藏,留给用户更多的位置来显示内容。
  • Behavior trees are used by AAA studios to create a lifelike AI. With Behavior Designer, you can bring the power of behaviour trees to Unity! Behavior Designer is a behaviour tree implementation ...
  • CoordinatorLayout高级用法-自定义Behavior

    万次阅读 多人点赞 2015-12-14 22:23:41
    在新的support design中,CoordinatorLayout可以说是最重要的一个控件了,CoordinatorLayout给我们带来了一种新的事件的处理方式——behavior,你是不是还记得我们在使用CoordinatorLayout的时候,一些子view需要一...
  • Unity 行为树 Behavior Designer

    万次阅读 2017-03-30 22:17:56
    Behavior Designer插件官方网站 目前在Unity3D游戏中一般复杂的AI都可以看到行为树的身影,简单的AI使用状态机来实现就可以了,所以这里我也是简单的学习下,为以后用到做准备。 行为树的概念出现已经很多年了,...
  • unity角色行为AI系统Behavior Designer - Movement Pack 1.5.4 所支持的Unity版本:4.6.0 及以上版本 Requires Behavior Designer Behavior Designer - Movement Pack contains 17 different behaviour tree tasks ...
  • 每个 behavior 可以包含一组属性、数据、生命周期函数和方法,组件引用它时,它的属性、数据和方法会被合并到组件中,生命周期函数也会在对应时机被调用。每个组件可以引用多个 behaviorbehavior 也可以引用其他...
1 2 3 4 5 ... 20
收藏数 171,855
精华内容 68,742
关键字:

behavior