代码之家  ›  专栏  ›  技术社区  ›  rgoncalv

如何使用协调器布局和行为在CardView上完成此动画?

  •  13
  • rgoncalv  · 技术社区  · 7 年前

    我试图通过协调器布局实现以下效果:

    enter image description here

    我花了大约30多个小时试图解决这个问题,我知道应该采取协调器布局行为,但我有很多地方做错了。

    以下是我的xml:

    <android.support.constraint.ConstraintLayout 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:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.StatisticsFragment">
    
    <!-- TODO: Update blank fragment layout -->
    
    <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"
        android:background="@android:color/background_light">
    
        <android.support.design.widget.AppBarLayout
            android:id="@+id/main.appbar"
            android:layout_width="match_parent"
            android:layout_height="137dp"
            android:background="@android:color/transparent">
    
            <android.support.design.widget.CollapsingToolbarLayout
                android:id="@+id/main.collapsing"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                app:layout_scrollFlags="scroll|exitUntilCollapsed"
                app:expandedTitleMarginStart="48dp"
                app:expandedTitleMarginEnd="64dp">
    
                <android.support.v7.widget.CardView
                    android:id="@+id/earningsCardView"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginEnd="8dp"
                    android:layout_marginStart="8dp"
                    android:layout_marginTop="8dp"
                    app:layout_constraintEnd_toEndOf="parent"
                    app:layout_constraintStart_toStartOf="parent"
                    app:layout_constraintTop_toTopOf="parent">
    
                    <android.support.constraint.ConstraintLayout
                        android:layout_width="match_parent"
                        android:layout_height="match_parent">
    
                        <android.support.v7.widget.AppCompatTextView
                            android:id="@+id/todayLabel"
                            android:layout_width="108dp"
                            android:layout_height="26dp"
                            android:layout_marginEnd="8dp"
                            android:layout_marginStart="8dp"
                            android:layout_marginTop="12dp"
                            android:gravity="center"
                            android:text="TODAY"
                            android:textAlignment="center"
                            android:textColor="@android:color/darker_gray"
                            android:textSize="18sp"
                           app:layout_constraintEnd_toStartOf="@+id/guideline"
                            app:layout_constraintStart_toStartOf="parent"
                            app:layout_constraintTop_toTopOf="parent" />
    
    
                        <android.support.v7.widget.AppCompatTextView
                            android:id="@+id/weekLabel"
                            android:layout_width="108dp"
                            android:layout_height="26dp"
                            android:layout_marginEnd="8dp"
                            android:layout_marginStart="8dp"
                            android:layout_marginTop="12dp"
                            android:gravity="center"
                            android:text="WEEK"
                            android:textAlignment="center"
                            android:textColor="@android:color/darker_gray"
                            android:textSize="18sp"
                            app:layout_constraintEnd_toEndOf="parent"
                            app:layout_constraintStart_toStartOf="@+id/guideline"
                            app:layout_constraintTop_toTopOf="parent" />
    
    
                        <android.support.v7.widget.AppCompatTextView
                            android:id="@+id/weekEarningsLabel"
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:layout_marginTop="8dp"
                            android:gravity="center"
                            android:text="$800"
                            android:textAlignment="center"
                            android:textColor="@color/colorAccent"
                            android:textSize="32sp"
                            app:layout_constraintEnd_toEndOf="@+id/todayLabel"
                            app:layout_constraintStart_toStartOf="@+id/todayLabel"
                            app:layout_constraintTop_toBottomOf="@+id/todayLabel" />
    
    
                        <android.support.v7.widget.AppCompatTextView
                            android:id="@+id/todayEarningsLabel"
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:layout_marginEnd="8dp"
                            android:layout_marginTop="8dp"
                            android:gravity="center"
                            android:text="$5200"
                            android:textAlignment="center"
                            android:textColor="@color/green_light"
                            android:textSize="32sp"
                            app:layout_constraintEnd_toEndOf="@+id/weekLabel"
                            app:layout_constraintStart_toStartOf="@+id/weekLabel"
                            app:layout_constraintTop_toBottomOf="@+id/weekLabel" />
    
                        <android.support.constraint.Guideline
                            android:id="@+id/guideline"
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:orientation="vertical"
                            app:layout_constraintEnd_toEndOf="parent"
                            app:layout_constraintGuide_percent="0.5012658"
                            app:layout_constraintHorizontal_bias="0.5"
                            app:layout_constraintStart_toStartOf="parent"/>
    
                        <android.support.v7.widget.AppCompatTextView
                            android:id="@+id/todayOrderAmount"
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:layout_marginTop="8dp"
                            android:layout_marginBottom="16dp"
                            android:text="18 deliveries"
                            android:textSize="12sp"
                            app:layout_constraintEnd_toEndOf="@+id/weekEarningsLabel"
                            app:layout_constraintStart_toStartOf="@+id/weekEarningsLabel"
                            app:layout_constraintTop_toBottomOf="@+id/weekEarningsLabel" />
    
                        <TextView
                            android:id="@+id/weekOrderAmount"
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:layout_marginEnd="8dp"
                            android:layout_marginStart="8dp"
                            android:layout_marginTop="8dp"
                            android:layout_marginBottom="8dp"
                            android:text="87 deliveries"
                            android:textSize="12sp"
                            app:layout_constraintEnd_toEndOf="@+id/todayEarningsLabel"
                            app:layout_constraintHorizontal_bias="0.51"
                            app:layout_constraintStart_toStartOf="@+id/todayEarningsLabel"
                            app:layout_constraintTop_toBottomOf="@+id/todayEarningsLabel" />
    
                    </android.support.constraint.ConstraintLayout>
    
                </android.support.v7.widget.CardView>
    
            </android.support.design.widget.CollapsingToolbarLayout>
        </android.support.design.widget.AppBarLayout>
    
        <android.support.v4.widget.NestedScrollView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_behavior="@string/appbar_scrolling_view_behavior">
    
            <android.support.v7.widget.RecyclerView
                android:id="@+id/historicRecyclerView"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toBottomOf="@+id/earningsCardView" />
        </android.support.v4.widget.NestedScrollView>
    </android.support.design.widget.CoordinatorLayout>
    

    我创建了一个行为子类,试图为今天的收益标签(绿色)设置动画:

    class TodayEarningsLabelBehavior : CoordinatorLayout.Behavior<TextView>() {
         override fun layoutDependsOn(parent: CoordinatorLayout?, child: TextView?, dependency: View?): Boolean {
            return dependency is CardView
         }
    
         override fun onDependentViewChanged(parent: CoordinatorLayout?, child: TextView?, dependency: View?): Boolean {
            if (child != null){
                child.textSize = dependency!!.height / 3.0F
            }
    
            return false
         }
    }
    

    但是如何在xml中设置此行为 app:layout_behavior 如果不是 CoordinatorLayout ?

    解决此问题的任何方法(可能不涉及 Coordinator Layout )也非常受欢迎。

    1 回复  |  直到 7 年前
        1
  •  11
  •   Omid Heshmatinia    7 年前

    给你:

    screenShot of the result

    有几个重要的注意事项:

    • 因为我们在scrollview中定义了回收器,所以它不会回收视图!!!!因此,尽量不要在列表中放置太多图形对象
    • 视图高度和宽度应在创建整个视图后计算。否则你会得到零。这就是我使用 globalLayoutListener

    我声明我的活动如下:

    public class CustomCardAnimationActivity extends AppCompatActivity {
    
    
    NestedScrollView scrollView;
    RecyclerView recyclerView;
    CardView cardView;
    TextView tvToday;
    TextView tvTodayPrice;
    TextView tvTodayDelivery;
    TextView tvWeek;
    TextView tvWeekPrice;
    TextView tvWeekDelivery;
    int cardHeight;
    int textViewHeight;
    float tvTitleTodayX;
    float tvPriceTodayX;
    float tvTitleWeekX;
    float tvPriceWeekX;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    
        setContentView(R.layout.activity_custom_card_animation);
    
        recyclerView= (RecyclerView) findViewById(R.id.recyclerView);
        scrollView= (NestedScrollView) findViewById(R.id.nested_scrollView);
        cardView= (CardView) findViewById(R.id.cardView);
        tvToday=(TextView) findViewById(R.id.textView_today);
        tvTodayPrice=(TextView) findViewById(R.id.textView_today_price);
        tvTodayDelivery=(TextView) findViewById(R.id.textView_today_delivery);
        tvWeek=(TextView) findViewById(R.id.textView_week);
        tvWeekPrice=(TextView) findViewById(R.id.textView_week_price);
        tvWeekDelivery=(TextView) findViewById(R.id.textView_week_delivery);
        scrollView.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {
            @Override
            public void onScrollChanged() {
                int scrollY = scrollView.getScrollY();
                FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) cardView.getLayoutParams();
                int height = Math.max(textViewHeight,cardHeight-scrollY);
                lp.height = height;
                cardView.setLayoutParams(lp);
    
                // alpha delivery textViews
                tvTodayDelivery.setAlpha(Math.max(0f,(float) ((cardHeight/2)-scrollY)/(cardHeight/2)));
                tvWeekDelivery.setAlpha(Math.max(0f,(float) ((cardHeight/2)-scrollY)/(cardHeight/2)));
    
                // move titles to left
                float titleMovementChange = Math.max(-scrollY , -textViewHeight);
                tvToday.setX(tvTitleTodayX + titleMovementChange);
                tvWeek.setX(tvTitleWeekX + titleMovementChange*1.2f);
    
                // move prices to right
                float priceMovementChange = Math.max(-scrollY , -textViewHeight/2);
                tvTodayPrice.setX(tvPriceTodayX - priceMovementChange);
                tvWeekPrice.setX(tvPriceWeekX - priceMovementChange * 1.2f);
            }
        });
    
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        recyclerView.setAdapter(new TestListAdapter());
        recyclerView.setNestedScrollingEnabled(false);
    
        //if you remove this part, the card would be shown in its minimum state at start
        recyclerView.post(new Runnable() {
            @Override
            public void run() {
                scrollView.scrollTo(0,0);
            }
        });
    
        // The calculation for heights of views should be done after the view created
        View rootView = findViewById(R.id.root_view);
        rootView.getViewTreeObserver().addOnGlobalLayoutListener(
                new ViewTreeObserver.OnGlobalLayoutListener() {
                    public void onGlobalLayout() {
                        //Remove the listener before proceeding
                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                            rootView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                        } else {
                            rootView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
                        }
    
                        // measure your views here
                        cardHeight = cardView.getHeight();
                        textViewHeight= tvToday.getHeight();
                        tvTitleTodayX = tvToday.getX();
                        tvPriceTodayX = tvTodayPrice.getX();
                        tvTitleWeekX = tvWeek.getX();
                        tvPriceWeekX = tvWeekPrice.getX();
                        scrollView.scrollTo(0,0);
                    }
                });
    }
    }
    

    此外,我的xml如下所示:

    <FrameLayout
    android:id="@+id/root_view"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:background="#0099cc"
    tools:context="com.bisphone.interviewtest.test.CustomCardAnimationActivity">
    
    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:padding="16dp">
        <android.support.v7.widget.CardView
            android:id="@+id/cardView"
            android:layout_width="match_parent"
            android:layout_height="100dp"
            android:layout_margin="16dp"
            app:cardElevation="4dp">
            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:orientation="horizontal">
            <FrameLayout
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_weight="1"
                android:gravity="center">
                <TextView
                    android:id="@+id/textView_today"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:gravity="center"
                    android:layout_gravity="top|center"
                    android:padding="8dp"
                    android:textSize="12sp"
                    android:text="TODAY"/>
    
                <TextView
                    android:id="@+id/textView_today_price"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="800 $"
                    android:gravity="center"
                    android:padding="8dp"
                    android:textSize="14sp"
                    android:textStyle="bold"
                    android:textAlignment="center"
                    android:layout_gravity="center"
                    android:textColor="#4caf50"/>
    
                <TextView
                    android:id="@+id/textView_today_delivery"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="18 Deliveries"
                    android:padding="8dp"
                    android:textSize="12sp"
                    android:layout_gravity="bottom|center"
                    android:gravity="center"/>
            </FrameLayout>
                <FrameLayout
                    android:layout_width="0dp"
                    android:layout_height="match_parent"
                    android:layout_weight="1"
                    android:gravity="center">
                    <TextView
                        android:id="@+id/textView_week"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:gravity="center"
                        android:layout_gravity="top|center"
                        android:textSize="12sp"
                        android:padding="8dp"
                        android:text="THIS WEEK"/>
    
                    <TextView
                        android:id="@+id/textView_week_price"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="5200 $"
                        android:textSize="14sp"
                        android:gravity="center"
                        android:layout_gravity="center"
                        android:textStyle="bold"
                        android:textAlignment="center"
                        android:textColor="#009688"/>
    
                    <TextView
                        android:id="@+id/textView_week_delivery"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="87 Deliveries"
                        android:layout_gravity="bottom|center"
                        android:textSize="12sp"
                        android:gravity="center"
                        android:padding="8dp"/>
                </FrameLayout>
            </LinearLayout>
        </android.support.v7.widget.CardView>
        <android.support.v7.widget.CardView
            android:layout_width="match_parent"
            android:layout_height="match_parent">
    
            <android.support.v4.widget.NestedScrollView
                android:id="@+id/nested_scrollView"
                android:layout_width="match_parent"
                android:layout_height="match_parent">
    
                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:orientation="vertical">
                    <FrameLayout
                        android:layout_width="match_parent"
                        android:layout_height="100dp"
                        android:layout_margin="16dp"/>
                    <android.support.v7.widget.RecyclerView
                        android:id="@+id/recyclerView"
                        android:layout_width="match_parent"
                        android:layout_height="match_parent"
                        android:nestedScrollingEnabled="false"/>
                </LinearLayout>
            </android.support.v4.widget.NestedScrollView>
        </android.support.v7.widget.CardView>
    
    </FrameLayout>