仿CoordinatorLayout的behavior动画

仿CoordinatorLayout的behavior动画

  1. 创建BehaviorRelativeLayout 继承 RelativeLayout 定义ViewGroup。

    BehaviorRelativeLayout的作用
    1、是记录子View中标记为Behavior的对象,将标记的VIew添加到List集合;
    2、当监听的将标记的子View循环出发进行动画。

    /**
        和系统自带的behavior没有关系 纯粹的思想相近
     */
    
    public class BehaviorRelativeLayout extends RelativeLayout {
        List<View> behaviorView = new ArrayList<>();
        public BehaviorRelativeLayout(Context context) {
            super(context);
        }
    
    public BehaviorRelativeLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    
    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        for (int i = 0; i < getChildCount(); i++) {
            View childAt = getChildAt(i);
            LayoutParams lp = (LayoutParams) childAt.getLayoutParams();
            if(lp.withBehavior){
                behaviorView.add(childAt);
            }
        }
    }
    
    public void allTranslationY(float transilationY){
        for (View view : behaviorView) {
            view.setTranslationY(transilationY);
        }
    }
    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);
    }
    
    @Override
    public LayoutParams generateLayoutParams(AttributeSet attrs) {
    
        return new LayoutParams(getContext(),attrs);
    }
    
      static  class LayoutParams extends RelativeLayout.LayoutParams{
            boolean withBehavior;
            public LayoutParams(Context c, AttributeSet attrs) {
                super(c, attrs);
                TypedArray a = c.obtainStyledAttributes(attrs,
                        R.styleable.BehaviorRelativeLayout);
                withBehavior = a.getBoolean(R.styleable.BehaviorRelativeLayout_withBehavior,false);
                a.recycle();
            }
        }
    }
    
  2. 自定义属性

    <resources>
        <declare-styleable name="BehaviorRelativeLayout">
            <attr name="withBehavior" format="boolean" />
        </declare-styleable>
    </resources>
    
  3. 添加需要监测的View, BottomPlaneChooseView,
    BottomPlaneChooseView包裹在BehaviorRelativeLayout 中,这里她是一个自定义VIewGroup在是一个底部的布局容器,我们onlayout()方法中得到父布局BehaviorRelativeLayout 对象,当我们点击BottomPlaneChooseView将其向Y正方向隐藏时调用BehaviorRelativeLayout 的mParent.allTranslationY(translationY)方法。

    BottomPlaneChooseView 类似NestedSrollView,被观察的View;
    作用:1. 根据BottomPlaneChooseView 的移动,来改变其他标记的子View的移动。

    public class BottomPlaneChooseView extends LinearLayout implements CompoundButton.OnCheckedChangeListener {
    
        private CheckBox mCbShowMore;
        private CheckBox mCbRotation;
    
        private TextView tvAddr;
        private TextView tvStatus;
    
        private Button btnChoosePlane;
    
        private int firstChildHei;
        private BehaviorRelativeLayout mParent;
    
        private PlaneAdapter mAdapter;
    
        private IBottomChooseViewListener mIChooseViewListener;
        private IBottomSwitchListener mBottomSwitchListener;
    
        public void setChooseViewListener(IBottomChooseViewListener listener) {
            mIChooseViewListener = listener;
        }
    
        public void setBottomSwitchListener(IBottomSwitchListener bottomSwitchListener) {
            if (bottomSwitchListener != null) {
                mBottomSwitchListener = bottomSwitchListener;
            }
        }
    
        public BottomPlaneChooseView(Context context) {
            super(context);
            init(context, null);
        }
    
        public BottomPlaneChooseView(Context context, @Nullable AttributeSet attrs) {
            super(context, attrs);
            init(context, attrs);
    
        }
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        }
    
        public void hideMore() {
            ObjectAnimator translationY = ObjectAnimator.ofFloat(this, "translationY", getTranslationY()
                    , getHeight());
            translationY.setDuration(200);
            translationY.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    super.onAnimationEnd(animation);
                    mBottomSwitchListener.onColseBottomView();
                }
            });
            translationY.start();
            mCbShowMore.setChecked(false);
        }
    
        public void showMore() {
            ObjectAnimator translationY = ObjectAnimator.ofFloat(this, "translationY", getTranslationY(), 0);
            translationY.setDuration(200);
            translationY.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationStart(Animator animation) {
                    super.onAnimationStart(animation);
                    mBottomSwitchListener.onOpenBottomView();
                }
            });
            translationY.start();
            mCbShowMore.setChecked(true);
        }
    
        @Override
        public void setTranslationY(float translationY) {
            super.setTranslationY(translationY);
    
            if (mParent != null) {
                mParent.allTranslationY(translationY);
            }
        }
    
        @Override
        protected void onLayout(boolean changed, int l, int t, int r, int b) {
            super.onLayout(changed, l, t, r, b);
            ViewParent parent = getParent();
    
            for (; ; ) {
                if (parent == null) break;
                if (parent instanceof BehaviorRelativeLayout) {
                    mParent = (BehaviorRelativeLayout) parent;
                    break;
                }
                parent = parent.getParent();
            }
        }
    
    
    
        public void init(Context context, AttributeSet attributeSet) {
            setOrientation(VERTICAL);
            LayoutInflater.from(context).inflate(R.layout.item_plane_choose, this, true);
            GridView gridView = findViewById(R.id.gv_plane_selected_list);
            ///gridView.setChoiceMode(GridView.CHOICE_MODE_SINGLE);
            mAdapter = new PlaneAdapter();
            gridView.setAdapter(mAdapter);
    
            mCbShowMore = (CheckBox) findViewById(R.id.cb_show_more);
            mCbRotation = (CheckBox) findViewById(R.id.cb_rotation);
            tvAddr = findViewById(R.id.tvAddr);
            tvStatus = findViewById(R.id.tvStatus);
            btnChoosePlane = findViewById(R.id.bt_choose_plane);
            setBtnChoosePlaneText(0);
            mCbShowMore.setOnCheckedChangeListener(this);
            mCbRotation.setOnCheckedChangeListener(this);
        }
    
        @Override
        public void setOnClickListener(@Nullable OnClickListener l) {
            super.setOnClickListener(l);
            setChildClickListener(this, l);
        }
    
        private void setChildClickListener(ViewGroup parent, OnClickListener l) {
            for (int i = 0; i < parent.getChildCount(); i++) {
                View childAt = parent.getChildAt(i);
                if (!(childAt instanceof AdapterView)) {
                    childAt.setOnClickListener(l);
                    if (childAt.isClickable() && childAt instanceof ViewGroup) {
                        setChildClickListener((ViewGroup) childAt, l);
                    }
                }
            }
        }
    
        @Override
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
            if (buttonView == mCbShowMore) {
                if (isChecked) {
                    showMore();
                } else {
                    hideMore();
                }
            } else if (buttonView == mCbRotation) {
                if (isChecked) {
                    for (int i = 0; i < mPlaneList.size(); i++) {
                        mPlaneList.get(i).isChoice = false;
                    }
                    mAdapter.notifyDataSetChanged();
                    mIChooseViewListener.onChooseChangeLoop(true);
                } else {
                    mIChooseViewListener.onChooseChangeLoop(false);
                }
            }
        }
    
        public void setChooseInfoView(PlaneChooseBean chooseBean) {
            tvAddr.setText(chooseBean.addr);
            tvStatus.setText(chooseBean.status);
            mPlaneList.clear();
            if (chooseBean.planeList.size() > 1) {
                mCbRotation.setChecked(true);
                for (ChoicePlaneInfo.PlaneInfo info : chooseBean.planeList) {
                    // 将传递过来选中的标志位置为未选择(默认不选中)
                    info.isChoice = false;
                }
            } else if (chooseBean.planeList.size() == 1) { // 只有一个默认选中
                mCbRotation.setChecked(false);
            }
            mPlaneList.addAll(chooseBean.planeList);
            setBtnChoosePlaneText(chooseBean.planeList.size());
            mAdapter.notifyDataSetChanged();
        }
    
        private void setBtnChoosePlaneText(int num) {
            String f_text = String.format(getContext().getString(R.string.choose_plane_format_num), num + "");
            btnChoosePlane.setText(f_text);
        }
    
        private List<ChoicePlaneInfo.PlaneInfo> mPlaneList = new ArrayList<>();
    
        class PlaneAdapter extends BaseAdapter {
    
            @Override
            public int getCount() {
                return mPlaneList.size();
            }
    
            @Override
            public Object getItem(int position) {
                return mPlaneList.get(position);
            }
    
            @Override
            public long getItemId(int position) {
                return position;
            }
    
            @Override
            public View getView(final int position, View convertView, ViewGroup parent) {
                VH vh;
                if (convertView == null) {
                    vh = new VH();
                    convertView = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_bottom_plane_name, parent, false);
                    vh.mTvPlaneName = (CheckedTextView) convertView.findViewById(R.id.tv_plane_name);
                    vh.mTvGroupName = (CheckedTextView) convertView.findViewById(R.id.tv_group_name);
                    convertView.setTag(vh);
                } else {
                    vh = (VH) convertView.getTag();
                }
    
                vh.mTvPlaneName.setText(mPlaneList.get(position).sn);
                vh.mTvGroupName.setText(mPlaneList.get(position).group);
    
                ((CheckLayout) convertView).setChecked(mPlaneList.get(position).isChoice);
    
                convertView.setOnClickListener(new OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        if (mIChooseViewListener != null) {
                            mPlaneList.get(position).isChoice = !mPlaneList.get(position).isChoice;
                            if (mPlaneList.get(position).isChoice) {
                                mIChooseViewListener.OnChoosePlaneClick(mPlaneList.get(position));
                                // 只选一架飞机,即当前飞机选择后其它飞机变不选择
                                for (int i = 0; i < mPlaneList.size(); i++) {
                                    if (i != position) {
                                        mPlaneList.get(i).isChoice = false;
                                    }
                                }
                                mCbRotation.setChecked(false);
                            } else {
                                mCbRotation.setChecked(true);
                            }
                            notifyDataSetChanged();
                        }
                    }
                });
    
                return convertView;
            }
    
            class VH {
                private CheckedTextView mTvPlaneName;
                private CheckedTextView mTvGroupName;
            }
        }
    
        public interface IBottomChooseViewListener {
            void OnChoosePlaneClick(ChoicePlaneInfo.PlaneInfo planeInfo);
    
            void onChooseChangeLoop(boolean isLoop);
        }
    
        public interface IBottomSwitchListener {
            void onOpenBottomView();
    
            void onColseBottomView();
        }
    }
    

BottomPlaneChooseView的xml布局

    <?xml version="1.0" encoding="utf-8"?>
    <merge 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"
           android:orientation="vertical">

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@color/colorPrimary"
            android:paddingEnd="@dimen/dp_8"
            android:paddingStart="@dimen/dp_12">

            <LinearLayout
                android:id="@+id/lay_left"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentStart="true"
                android:layout_centerVertical="true"
                android:gravity="center_vertical"
                android:orientation="horizontal">

                <CheckBox
                    android:id="@+id/cb_show_more"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_gravity="center"
                    android:button="@drawable/full_screen_selector"
                    android:checked="true"
                    android:gravity="center"
                    android:paddingTop="@dimen/dp_8"
                    android:paddingBottom="@dimen/dp_8"
                    android:paddingEnd="@dimen/dp_12"/>


                <View
                    android:layout_width="@dimen/normal_deliver_dimen"
                    android:layout_height="match_parent"
                    android:layout_marginBottom="@dimen/dp_8"
                    android:layout_marginTop="@dimen/dp_8"
                    android:layout_marginEnd="@dimen/dp_4"
                    android:background="@color/white"/>
            </LinearLayout>


            <Button
                android:id="@+id/bt_choose_plane"
                android:layout_width="@dimen/dp_70"
                android:layout_height="@dimen/dp_20"
                android:layout_alignParentEnd="true"
                android:layout_centerVertical="true"
                android:layout_marginStart="@dimen/dp_12"
                android:background="@drawable/select_choose_plane"
                android:gravity="center"
                android:stateListAnimator="@null"
                android:text="@string/choose_plane_format_num"
                android:textColor="@color/colorPrimary"
                android:textSize="@dimen/sp_7"
                />
            <!--android:theme="@style/button_style"-->

            <HorizontalScrollView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_centerVertical="true"
                android:layout_toLeftOf="@id/bt_choose_plane"
                android:layout_toRightOf="@id/lay_left"
                android:scrollbars="none">

                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:orientation="horizontal"
                    android:paddingLeft="@dimen/dp_6">

                    <TextView
                        android:id="@+id/tvAddr"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_marginEnd="@dimen/dp_4"
                        android:drawableEnd="@mipmap/icon_arrow_white"
                        android:drawableLeft="@mipmap/icon_region"
                        android:drawablePadding="@dimen/dp_4"
                        android:drawableStart="@mipmap/icon_region"
                        android:padding="@dimen/dp_6"
                        android:text="地区"
                        android:textColor="@color/white"
                        android:textSize="@dimen/sp_9"/>

                    <TextView
                        android:id="@+id/tvStatus"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_marginEnd="@dimen/dp_6"
                        android:drawableEnd="@mipmap/icon_arrow_white"
                        android:drawableLeft="@mipmap/icon_state"
                        android:drawablePadding="@dimen/dp_4"
                        android:drawableStart="@mipmap/icon_state"
                        android:padding="@dimen/dp_6"
                        android:text="状态"
                        android:textColor="@color/white"
                        android:textSize="@dimen/sp_9"/>

                    <CheckBox
                        android:id="@+id/cb_rotation"
                        android:layout_width="wrap_content"
                        android:layout_height="match_parent"
                        android:button="@drawable/rotation_selector"
                        android:checked="true"
                        android:paddingEnd="@dimen/dp_4"
                        android:paddingStart="@dimen/dp_4"
                        android:layout_marginLeft="@dimen/dp_2"
                        android:text="@string/rotation"
                        android:textColor="@color/white"
                        android:textSize="@dimen/sp_8"/>

                    <ImageView
                        android:id="@+id/v_set_loop_time"
                        android:layout_width="wrap_content"
                        android:layout_height="match_parent"
                        android:paddingEnd="@dimen/dp_12"
                        android:scaleType="centerInside"
                        android:src="@mipmap/btn_edit_1"/>

                </LinearLayout>
            </HorizontalScrollView>
        </RelativeLayout>


        <GridView
            android:id="@+id/gv_plane_selected_list"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:columnWidth="@dimen/dp_80"
            android:gravity="center"
            android:horizontalSpacing="@dimen/dp_8"
            android:maxHeight="@dimen/dp_62"
            android:numColumns="5"
            android:padding="@dimen/dp_8"
            android:scrollbars="none"
            android:verticalSpacing="@dimen/dp_8"
            android:visibility="visible"/>
    </merge>
  1. BehaviorRelativeLayou 在 xml布局使用
    将BehaviorRelativeLayout自定义ViewGroup放在布局的最外层,然后在需要移动的子View上添加withBehavior自定义属性。

    <com.cfuas.info.widget.BehaviorRelativeLayout
        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/root"
        android:layout_width="match_parent"
     android:layout_height="match_parent">
    
         <com.cfuas.info.widget.BottomPlaneChooseView
            android:id="@+id/bpcv_plane_choose_view"
            android:layout_width="match_parent"
            android:layout_height="@dimen/bottom_plane_choose_height"
            android:background="@color/bottom_view_bg_color"
            android:layout_alignParentBottom="true"
            android:layout_alignParentStart="true"/>
    
    <ImageView
            android:id="@+id/iv_switch_bottom"
            android:layout_width="@dimen/dp_24"
            android:layout_height="@dimen/dp_24"
            android:src="@drawable/select_bottom_switch"
            android:layout_above="@+id/bpcv_plane_choose_view"
            android:layout_alignParentStart="true"
            android:layout_marginBottom="@dimen/dp_8"
            android:layout_marginEnd="@dimen/dp_8"
            android:layout_marginStart="@dimen/dp_8"
            app:withBehavior="true"
            android:visibility="gone"
            />
    
    
    </com.cfuas.info.widget.BehaviorRelativeLayout>
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值