ExpandingEntryCardView.java revision 6b6328915d66f0c5947badc3d1973c31f29eef62
1/* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16package com.android.contacts.quickcontact; 17 18import android.content.Context; 19import android.content.Intent; 20import android.content.res.Resources; 21import android.graphics.ColorFilter; 22import android.graphics.Rect; 23import android.graphics.drawable.Drawable; 24import android.text.TextUtils; 25import android.transition.ChangeBounds; 26import android.transition.ChangeScroll; 27import android.transition.Fade; 28import android.transition.Transition; 29import android.transition.Transition.TransitionListener; 30import android.transition.TransitionManager; 31import android.transition.TransitionSet; 32import android.util.AttributeSet; 33import android.util.Log; 34import android.view.LayoutInflater; 35import android.view.TouchDelegate; 36import android.view.View; 37import android.view.ViewGroup; 38import android.widget.ImageView; 39import android.widget.LinearLayout; 40import android.widget.RelativeLayout; 41import android.widget.TextView; 42 43import com.android.contacts.R; 44 45import java.util.ArrayList; 46import java.util.List; 47 48/** 49 * Display entries in a LinearLayout that can be expanded to show all entries. 50 */ 51public class ExpandingEntryCardView extends LinearLayout { 52 53 private static final String TAG = "ExpandingEntryCardView"; 54 private static final int DURATION_EXPAND_ANIMATION_FADE_IN = 200; 55 private static final int DELAY_EXPAND_ANIMATION_FADE_IN = 100; 56 57 public static final int DURATION_EXPAND_ANIMATION_CHANGE_BOUNDS = 300; 58 public static final int DURATION_COLLAPSE_ANIMATION_CHANGE_BOUNDS = 300; 59 60 /** 61 * Entry data. 62 */ 63 public static final class Entry { 64 65 private final int mViewId; 66 private final Drawable mIcon; 67 private final String mHeader; 68 private final String mSubHeader; 69 private final Drawable mSubHeaderIcon; 70 private final String mText; 71 private final Drawable mTextIcon; 72 private final Intent mIntent; 73 private final Drawable mAlternateIcon; 74 private final Intent mAlternateIntent; 75 private final String mAlternateContentDescription; 76 private final boolean mShouldApplyColor; 77 private final boolean mIsEditable; 78 79 public Entry(int viewId, Drawable icon, String header, String subHeader, String text, 80 Intent intent, Drawable alternateIcon, Intent alternateIntent, 81 String alternateContentDescription, boolean shouldApplyColor, 82 boolean isEditable) { 83 this(viewId, icon, header, subHeader, null, text, null, intent, alternateIcon, 84 alternateIntent, alternateContentDescription, shouldApplyColor, isEditable); 85 } 86 87 public Entry(int viewId, Drawable mainIcon, String header, String subHeader, 88 Drawable subHeaderIcon, String text, Drawable textIcon, Intent intent, 89 Drawable alternateIcon, Intent alternateIntent, String alternateContentDescription, 90 boolean shouldApplyColor, boolean isEditable) { 91 mViewId = viewId; 92 mIcon = mainIcon; 93 mHeader = header; 94 mSubHeader = subHeader; 95 mSubHeaderIcon = subHeaderIcon; 96 mText = text; 97 mTextIcon = textIcon; 98 mIntent = intent; 99 mAlternateIcon = alternateIcon; 100 mAlternateIntent = alternateIntent; 101 mAlternateContentDescription = alternateContentDescription; 102 mShouldApplyColor = shouldApplyColor; 103 mIsEditable = isEditable; 104 } 105 106 Drawable getIcon() { 107 return mIcon; 108 } 109 110 String getHeader() { 111 return mHeader; 112 } 113 114 String getSubHeader() { 115 return mSubHeader; 116 } 117 118 Drawable getSubHeaderIcon() { 119 return mSubHeaderIcon; 120 } 121 122 public String getText() { 123 return mText; 124 } 125 126 Drawable getTextIcon() { 127 return mTextIcon; 128 } 129 130 Intent getIntent() { 131 return mIntent; 132 } 133 134 Drawable getAlternateIcon() { 135 return mAlternateIcon; 136 } 137 138 Intent getAlternateIntent() { 139 return mAlternateIntent; 140 } 141 142 String getAlternateContentDescription() { 143 return mAlternateContentDescription; 144 } 145 146 boolean shouldApplyColor() { 147 return mShouldApplyColor; 148 } 149 150 boolean isEditable() { 151 return mIsEditable; 152 } 153 154 int getViewId() { 155 return mViewId; 156 } 157 } 158 159 public interface ExpandingEntryCardViewListener { 160 void onCollapse(int heightDelta); 161 void onExpand(int heightDelta); 162 } 163 164 private View mExpandCollapseButton; 165 private TextView mExpandCollapseTextView; 166 private TextView mTitleTextView; 167 private CharSequence mExpandButtonText; 168 private CharSequence mCollapseButtonText; 169 private OnClickListener mOnClickListener; 170 private boolean mIsExpanded = false; 171 private int mCollapsedEntriesCount; 172 private ExpandingEntryCardViewListener mListener; 173 private List<List<Entry>> mEntries; 174 private int mNumEntries = 0; 175 private boolean mAllEntriesInflated = false; 176 private List<List<View>> mEntryViews; 177 private LinearLayout mEntriesViewGroup; 178 private final Drawable mCollapseArrowDrawable; 179 private final Drawable mExpandArrowDrawable; 180 private int mThemeColor; 181 private ColorFilter mThemeColorFilter; 182 private boolean mIsAlwaysExpanded; 183 /** The ViewGroup to run the expand/collapse animation on */ 184 private ViewGroup mAnimationViewGroup; 185 private LinearLayout mBadgeContainer; 186 private final List<ImageView> mBadges; 187 188 private final OnClickListener mExpandCollapseButtonListener = new OnClickListener() { 189 @Override 190 public void onClick(View v) { 191 if (mIsExpanded) { 192 collapse(); 193 } else { 194 expand(); 195 } 196 } 197 }; 198 199 public ExpandingEntryCardView(Context context) { 200 this(context, null); 201 } 202 203 public ExpandingEntryCardView(Context context, AttributeSet attrs) { 204 super(context, attrs); 205 LayoutInflater inflater = LayoutInflater.from(context); 206 View expandingEntryCardView = inflater.inflate(R.layout.expanding_entry_card_view, this); 207 mEntriesViewGroup = (LinearLayout) 208 expandingEntryCardView.findViewById(R.id.content_area_linear_layout); 209 mTitleTextView = (TextView) expandingEntryCardView.findViewById(R.id.title); 210 mCollapseArrowDrawable = 211 getResources().getDrawable(R.drawable.expanding_entry_card_collapse_white_24); 212 mExpandArrowDrawable = 213 getResources().getDrawable(R.drawable.expanding_entry_card_expand_white_24); 214 215 mExpandCollapseButton = inflater.inflate( 216 R.layout.quickcontact_expanding_entry_card_button, this, false); 217 mExpandCollapseTextView = (TextView) mExpandCollapseButton.findViewById(R.id.text); 218 mExpandCollapseButton.setOnClickListener(mExpandCollapseButtonListener); 219 mBadgeContainer = (LinearLayout) mExpandCollapseButton.findViewById(R.id.badge_container); 220 221 mBadges = new ArrayList<ImageView>(); 222 } 223 224 /** 225 * Sets the Entry list to display. 226 * 227 * @param entries The Entry list to display. 228 */ 229 public void initialize(List<List<Entry>> entries, int numInitialVisibleEntries, 230 boolean isExpanded, boolean isAlwaysExpanded, 231 ExpandingEntryCardViewListener listener, ViewGroup animationViewGroup) { 232 LayoutInflater layoutInflater = LayoutInflater.from(getContext()); 233 mIsExpanded = isExpanded; 234 mIsAlwaysExpanded = isAlwaysExpanded; 235 // If isAlwaysExpanded is true, mIsExpanded should be true 236 mIsExpanded |= mIsAlwaysExpanded; 237 mEntryViews = new ArrayList<List<View>>(entries.size()); 238 mEntries = entries; 239 mNumEntries = 0; 240 mAllEntriesInflated = false; 241 for (List<Entry> entryList : mEntries) { 242 mNumEntries += entryList.size(); 243 mEntryViews.add(new ArrayList<View>()); 244 } 245 mCollapsedEntriesCount = Math.min(numInitialVisibleEntries, mNumEntries); 246 // Only show the head of each entry list if the initial visible number falls between the 247 // number of lists and the total number of entries 248 if (mCollapsedEntriesCount > mEntries.size()) { 249 mCollapsedEntriesCount = mEntries.size(); 250 } 251 mListener = listener; 252 mAnimationViewGroup = animationViewGroup; 253 254 if (mIsExpanded) { 255 updateExpandCollapseButton(getCollapseButtonText()); 256 inflateAllEntries(layoutInflater); 257 } else { 258 updateExpandCollapseButton(getExpandButtonText()); 259 inflateInitialEntries(layoutInflater); 260 } 261 insertEntriesIntoViewGroup(); 262 applyColor(); 263 } 264 265 /** 266 * Sets the text for the expand button. 267 * 268 * @param expandButtonText The expand button text. 269 */ 270 public void setExpandButtonText(CharSequence expandButtonText) { 271 mExpandButtonText = expandButtonText; 272 if (mExpandCollapseTextView != null && !mIsExpanded) { 273 mExpandCollapseTextView.setText(expandButtonText); 274 } 275 } 276 277 /** 278 * Sets the text for the expand button. 279 * 280 * @param expandButtonText The expand button text. 281 */ 282 public void setCollapseButtonText(CharSequence expandButtonText) { 283 mCollapseButtonText = expandButtonText; 284 if (mExpandCollapseTextView != null && mIsExpanded) { 285 mExpandCollapseTextView.setText(mCollapseButtonText); 286 } 287 } 288 289 @Override 290 public void setOnClickListener(OnClickListener listener) { 291 mOnClickListener = listener; 292 } 293 294 private void insertEntriesIntoViewGroup() { 295 mEntriesViewGroup.removeAllViews(); 296 297 if (mIsExpanded) { 298 for (List<View> viewList : mEntryViews) { 299 for (View view : viewList) { 300 addEntry(view); 301 } 302 } 303 } else { 304 for (int i = 0; i < mCollapsedEntriesCount; i++) { 305 addEntry(mEntryViews.get(i).get(0)); 306 } 307 } 308 309 removeView(mExpandCollapseButton); 310 if (mCollapsedEntriesCount < mNumEntries 311 && mExpandCollapseButton.getParent() == null && !mIsAlwaysExpanded) { 312 addView(mExpandCollapseButton, -1); 313 } 314 } 315 316 private void addEntry(View entry) { 317 if (mEntriesViewGroup.getChildCount() > 0) { 318 mEntriesViewGroup.addView(createSeparator(entry)); 319 } 320 mEntriesViewGroup.addView(entry); 321 } 322 323 private View createSeparator(View entry) { 324 View separator = new View(getContext()); 325 separator.setBackgroundColor(getResources().getColor( 326 R.color.expanding_entry_card_item_separator_color)); 327 LayoutParams layoutParams = generateDefaultLayoutParams(); 328 Resources resources = getResources(); 329 layoutParams.height = resources.getDimensionPixelSize( 330 R.dimen.expanding_entry_card_item_separator_height); 331 // The separator is aligned with the text in the entry. This is offset by a default 332 // margin. If there is an icon present, the icon's width and margin are added 333 int marginStart = resources.getDimensionPixelSize( 334 R.dimen.expanding_entry_card_item_padding_start); 335 ImageView entryIcon = (ImageView) entry.findViewById(R.id.icon); 336 if (entryIcon.getDrawable() != null) { 337 int imageWidthAndMargin = 338 resources.getDimensionPixelSize( 339 R.dimen.expanding_entry_card_item_icon_width) + 340 resources.getDimensionPixelSize( 341 R.dimen.expanding_entry_card_item_image_spacing); 342 marginStart += imageWidthAndMargin; 343 } 344 if (getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) { 345 layoutParams.rightMargin = marginStart; 346 } else { 347 layoutParams.leftMargin = marginStart; 348 } 349 separator.setLayoutParams(layoutParams); 350 return separator; 351 } 352 353 private CharSequence getExpandButtonText() { 354 if (!TextUtils.isEmpty(mExpandButtonText)) { 355 return mExpandButtonText; 356 } else { 357 // Default to "See more". 358 return getResources().getText(R.string.expanding_entry_card_view_see_more); 359 } 360 } 361 362 private CharSequence getCollapseButtonText() { 363 if (!TextUtils.isEmpty(mCollapseButtonText)) { 364 return mCollapseButtonText; 365 } else { 366 // Default to "See less". 367 return getResources().getText(R.string.expanding_entry_card_view_see_less); 368 } 369 } 370 371 /** 372 * Inflates the initial entries to be shown. 373 */ 374 private void inflateInitialEntries(LayoutInflater layoutInflater) { 375 // If the number of collapsed entries equals total entries, inflate all 376 if (mCollapsedEntriesCount == mNumEntries) { 377 inflateAllEntries(layoutInflater); 378 } else { 379 // Otherwise inflate the top entry from each list 380 for (int i = 0; i < mCollapsedEntriesCount; i++) { 381 mEntryViews.get(i).add(createEntryView(layoutInflater, mEntries.get(i).get(0))); 382 } 383 } 384 } 385 386 /** 387 * Inflates all entries. 388 */ 389 private void inflateAllEntries(LayoutInflater layoutInflater) { 390 if (mAllEntriesInflated) { 391 return; 392 } 393 for (int i = 0; i < mEntries.size(); i++) { 394 List<Entry> entryList = mEntries.get(i); 395 List<View> viewList = mEntryViews.get(i); 396 for (int j = viewList.size(); j < entryList.size(); j++) { 397 viewList.add(createEntryView(layoutInflater, entryList.get(j))); 398 } 399 } 400 mAllEntriesInflated = true; 401 } 402 403 public void setColorAndFilter(int color, ColorFilter colorFilter) { 404 mThemeColor = color; 405 mThemeColorFilter = colorFilter; 406 applyColor(); 407 } 408 409 public void setEntryHeaderColor(int color) { 410 if (mEntries != null) { 411 for (List<View> entryList : mEntryViews) { 412 for (View entryView : entryList) { 413 TextView header = (TextView) entryView.findViewById(R.id.header); 414 if (header != null) { 415 header.setTextColor(color); 416 } 417 } 418 } 419 } 420 } 421 422 /** 423 * The ColorFilter is passed in along with the color so that a new one only needs to be created 424 * once for the entire activity. 425 * 1. Title 426 * 2. Entry icons 427 * 3. Expand/Collapse Text 428 * 4. Expand/Collapse Button 429 */ 430 public void applyColor() { 431 if (mThemeColor != 0 && mThemeColorFilter != null) { 432 // Title 433 if (mTitleTextView != null) { 434 mTitleTextView.setTextColor(mThemeColor); 435 } 436 437 // Entry icons 438 if (mEntries != null) { 439 for (List<Entry> entryList : mEntries) { 440 for (Entry entry : entryList) { 441 if (entry.shouldApplyColor()) { 442 Drawable icon = entry.getIcon(); 443 if (icon != null) { 444 icon.setColorFilter(mThemeColorFilter); 445 } 446 } 447 Drawable alternateIcon = entry.getAlternateIcon(); 448 if (alternateIcon != null) { 449 alternateIcon.setColorFilter(mThemeColorFilter); 450 } 451 } 452 } 453 } 454 455 // Expand/Collapse 456 mExpandCollapseTextView.setTextColor(mThemeColor); 457 mCollapseArrowDrawable.setColorFilter(mThemeColorFilter); 458 mExpandArrowDrawable.setColorFilter(mThemeColorFilter); 459 } 460 } 461 462 private View createEntryView(LayoutInflater layoutInflater, Entry entry) { 463 final View view = layoutInflater.inflate( 464 R.layout.expanding_entry_card_item, this, false); 465 466 view.setId(entry.getViewId()); 467 468 final ImageView icon = (ImageView) view.findViewById(R.id.icon); 469 if (entry.getIcon() != null) { 470 icon.setImageDrawable(entry.getIcon()); 471 } else { 472 icon.setVisibility(View.GONE); 473 } 474 475 final TextView header = (TextView) view.findViewById(R.id.header); 476 if (!TextUtils.isEmpty(entry.getHeader())) { 477 header.setText(entry.getHeader()); 478 } else { 479 header.setVisibility(View.GONE); 480 } 481 482 final TextView subHeader = (TextView) view.findViewById(R.id.sub_header); 483 if (!TextUtils.isEmpty(entry.getSubHeader())) { 484 subHeader.setText(entry.getSubHeader()); 485 } else { 486 subHeader.setVisibility(View.GONE); 487 } 488 489 final ImageView subHeaderIcon = (ImageView) view.findViewById(R.id.icon_sub_header); 490 if (entry.getSubHeaderIcon() != null) { 491 subHeaderIcon.setImageDrawable(entry.getSubHeaderIcon()); 492 } else { 493 subHeaderIcon.setVisibility(View.GONE); 494 } 495 496 final TextView text = (TextView) view.findViewById(R.id.text); 497 if (!TextUtils.isEmpty(entry.getText())) { 498 text.setText(entry.getText()); 499 } else { 500 text.setVisibility(View.GONE); 501 } 502 503 final ImageView textIcon = (ImageView) view.findViewById(R.id.icon_text); 504 if (entry.getTextIcon() != null) { 505 textIcon.setImageDrawable(entry.getTextIcon()); 506 } else { 507 textIcon.setVisibility(View.GONE); 508 } 509 510 if (entry.getIntent() != null) { 511 view.setOnClickListener(mOnClickListener); 512 view.setTag(entry.getIntent()); 513 } 514 515 // If only the header is visible, add a top margin to match icon's top margin 516 if (header.getVisibility() == View.VISIBLE && subHeader.getVisibility() == View.GONE && 517 text.getVisibility() == View.GONE) { 518 RelativeLayout.LayoutParams headerLayoutParams = 519 (RelativeLayout.LayoutParams) header.getLayoutParams(); 520 headerLayoutParams.topMargin = (int) (getResources().getDimension( 521 R.dimen.expanding_entry_card_item_icon_margin_top)); 522 header.setLayoutParams(headerLayoutParams); 523 } 524 525 final ImageView alternateIcon = (ImageView) view.findViewById(R.id.icon_alternate); 526 if (entry.getAlternateIcon() != null && entry.getAlternateIntent() != null) { 527 alternateIcon.setImageDrawable(entry.getAlternateIcon()); 528 alternateIcon.setOnClickListener(mOnClickListener); 529 alternateIcon.setTag(entry.getAlternateIntent()); 530 alternateIcon.setId(entry.getViewId()); 531 alternateIcon.setVisibility(View.VISIBLE); 532 alternateIcon.setContentDescription(entry.getAlternateContentDescription()); 533 534 // Expand the clickable area for alternate icon to be top to bottom and to end edge 535 // of the entry view 536 view.post(new Runnable() { 537 @Override 538 public void run() { 539 final Rect alternateIconRect = new Rect(); 540 alternateIcon.getHitRect(alternateIconRect); 541 542 alternateIconRect.bottom = view.getHeight(); 543 alternateIconRect.top = 0; 544 if (getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) { 545 alternateIconRect.left = 0; 546 } else { 547 alternateIconRect.right = view.getWidth(); 548 } 549 final TouchDelegate touchDelegate = 550 new TouchDelegate(alternateIconRect, alternateIcon); 551 view.setTouchDelegate(touchDelegate); 552 } 553 }); 554 } 555 556 return view; 557 } 558 559 private void updateExpandCollapseButton(CharSequence buttonText) { 560 final Drawable arrow = mIsExpanded ? mCollapseArrowDrawable : mExpandArrowDrawable; 561 updateBadges(); 562 if (getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) { 563 mExpandCollapseTextView.setCompoundDrawablesWithIntrinsicBounds(null, null, arrow, 564 null); 565 } else { 566 mExpandCollapseTextView.setCompoundDrawablesWithIntrinsicBounds(arrow, null, null, 567 null); 568 } 569 mExpandCollapseTextView.setText(buttonText); 570 } 571 572 private void updateBadges() { 573 if (mIsExpanded) { 574 mBadgeContainer.removeAllViews(); 575 } else { 576 // Inflate badges if not yet created 577 if (mBadges.size() < mEntries.size() - mCollapsedEntriesCount) { 578 for (int i = mCollapsedEntriesCount; i < mEntries.size(); i++) { 579 Drawable badgeDrawable = mEntries.get(i).get(0).getIcon(); 580 if (badgeDrawable != null) { 581 ImageView badgeView = new ImageView(getContext()); 582 LinearLayout.LayoutParams badgeViewParams = new LinearLayout.LayoutParams( 583 (int) getResources().getDimension( 584 R.dimen.expanding_entry_card_item_icon_width), 585 (int) getResources().getDimension( 586 R.dimen.expanding_entry_card_item_icon_height)); 587 badgeViewParams.setMarginEnd((int) getResources().getDimension( 588 R.dimen.expanding_entry_card_badge_separator_margin)); 589 badgeView.setLayoutParams(badgeViewParams); 590 badgeView.setImageDrawable(badgeDrawable); 591 mBadges.add(badgeView); 592 } 593 } 594 } 595 mBadgeContainer.removeAllViews(); 596 for (ImageView badge : mBadges) { 597 mBadgeContainer.addView(badge); 598 } 599 } 600 } 601 602 private void expand() { 603 ChangeBounds boundsTransition = new ChangeBounds(); 604 boundsTransition.setDuration(DURATION_EXPAND_ANIMATION_CHANGE_BOUNDS); 605 606 Fade fadeIn = new Fade(Fade.IN); 607 fadeIn.setDuration(DURATION_EXPAND_ANIMATION_FADE_IN); 608 fadeIn.setStartDelay(DELAY_EXPAND_ANIMATION_FADE_IN); 609 610 TransitionSet transitionSet = new TransitionSet(); 611 transitionSet.addTransition(boundsTransition); 612 transitionSet.addTransition(fadeIn); 613 614 final ViewGroup transitionViewContainer = mAnimationViewGroup == null ? 615 this : mAnimationViewGroup; 616 617 transitionSet.addListener(new TransitionListener() { 618 @Override 619 public void onTransitionStart(Transition transition) { 620 // The listener is used to turn off suppressing, the proper delta is not necessary 621 mListener.onExpand(0); 622 } 623 624 @Override 625 public void onTransitionEnd(Transition transition) { 626 } 627 628 @Override 629 public void onTransitionCancel(Transition transition) { 630 } 631 632 @Override 633 public void onTransitionPause(Transition transition) { 634 } 635 636 @Override 637 public void onTransitionResume(Transition transition) { 638 } 639 }); 640 641 TransitionManager.beginDelayedTransition(transitionViewContainer, transitionSet); 642 643 mIsExpanded = true; 644 // In order to insert new entries, we may need to inflate them for the first time 645 inflateAllEntries(LayoutInflater.from(getContext())); 646 insertEntriesIntoViewGroup(); 647 updateExpandCollapseButton(getCollapseButtonText()); 648 } 649 650 private void collapse() { 651 final int startingHeight = mEntriesViewGroup.getMeasuredHeight(); 652 mIsExpanded = false; 653 updateExpandCollapseButton(getExpandButtonText()); 654 655 final ChangeBounds boundsTransition = new ChangeBounds(); 656 boundsTransition.setDuration(DURATION_COLLAPSE_ANIMATION_CHANGE_BOUNDS); 657 658 final ChangeScroll scrollTransition = new ChangeScroll(); 659 scrollTransition.setDuration(DURATION_COLLAPSE_ANIMATION_CHANGE_BOUNDS); 660 661 TransitionSet transitionSet = new TransitionSet(); 662 transitionSet.addTransition(boundsTransition); 663 transitionSet.addTransition(scrollTransition); 664 665 final ViewGroup transitionViewContainer = mAnimationViewGroup == null ? 666 this : mAnimationViewGroup; 667 668 boundsTransition.addListener(new TransitionListener() { 669 @Override 670 public void onTransitionStart(Transition transition) { 671 /* 672 * onTransitionStart is called after the view hierarchy has been changed but before 673 * the animation begins. 674 */ 675 int finishingHeight = mEntriesViewGroup.getMeasuredHeight(); 676 mListener.onCollapse(startingHeight - finishingHeight); 677 } 678 679 @Override 680 public void onTransitionEnd(Transition transition) { 681 } 682 683 @Override 684 public void onTransitionCancel(Transition transition) { 685 } 686 687 @Override 688 public void onTransitionPause(Transition transition) { 689 } 690 691 @Override 692 public void onTransitionResume(Transition transition) { 693 } 694 }); 695 696 TransitionManager.beginDelayedTransition(transitionViewContainer, transitionSet); 697 698 insertEntriesIntoViewGroup(); 699 } 700 701 /** 702 * Returns whether the view is currently in its expanded state. 703 */ 704 public boolean isExpanded() { 705 return mIsExpanded; 706 } 707 708 /** 709 * Sets the title text of this ExpandingEntryCardView. 710 * @param title The title to set. A null title will result in the title being removed. 711 */ 712 public void setTitle(String title) { 713 if (mTitleTextView == null) { 714 Log.e(TAG, "mTitleTextView is null"); 715 } 716 if (title == null) { 717 mTitleTextView.setVisibility(View.GONE); 718 findViewById(R.id.title_separator).setVisibility(View.GONE); 719 } 720 mTitleTextView.setText(title); 721 mTitleTextView.setVisibility(View.VISIBLE); 722 findViewById(R.id.title_separator).setVisibility(View.VISIBLE); 723 } 724 725 public boolean shouldShow() { 726 return mEntries != null && mEntries.size() > 0; 727 } 728} 729