Example usage for android.view ViewTreeObserver addOnPreDrawListener

List of usage examples for android.view ViewTreeObserver addOnPreDrawListener

Introduction

In this page you can find the example usage for android.view ViewTreeObserver addOnPreDrawListener.

Prototype

public void addOnPreDrawListener(OnPreDrawListener listener) 

Source Link

Document

Register a callback to be invoked when the view tree is about to be drawn

Usage

From source file:com.audiokernel.euphonyrmt.fragments.SongsFragment.java

@Override
public View onCreateView(final LayoutInflater inflater, final ViewGroup container,
        final Bundle savedInstanceState) {
    final View view = inflater.inflate(R.layout.songs, container, false);
    mList = (AbsListView) view.findViewById(R.id.list);
    registerForContextMenu(mList);/*  w w w .  j  a  v a 2 s  . c  om*/
    mList.setOnItemClickListener(this);

    mLoadingView = view.findViewById(R.id.loadingLayout);
    mLoadingTextView = (TextView) view.findViewById(R.id.loadingText);
    mNoResultView = view.findViewById(R.id.noResultLayout);
    mLoadingTextView.setText(getLoadingText());

    final View headerView = inflater.inflate(R.layout.song_header, null, false);
    mCoverArt = (ImageView) view.findViewById(R.id.albumCover);
    if (mCoverArt != null) {
        mHeaderArtist = (TextView) view.findViewById(R.id.tracks_artist);
        mHeaderInfo = (TextView) view.findViewById(R.id.tracks_info);
        mCoverArtProgress = (ProgressBar) view.findViewById(R.id.albumCoverProgress);
        mAlbumMenu = (ImageButton) view.findViewById(R.id.album_menu);
    } else {
        mHeaderArtist = (TextView) headerView.findViewById(R.id.tracks_artist);
        mHeaderInfo = (TextView) headerView.findViewById(R.id.tracks_info);
        mCoverArt = (ImageView) headerView.findViewById(R.id.albumCover);
        mCoverArtProgress = (ProgressBar) headerView.findViewById(R.id.albumCoverProgress);
        mAlbumMenu = (ImageButton) headerView.findViewById(R.id.album_menu);
    }

    mCoverArtListener = new AlbumCoverDownloadListener(mCoverArt, mCoverArtProgress, false);
    mCoverHelper = new CoverAsyncHelper();
    mCoverHelper.setCoverMaxSizeFromScreen(getActivity());
    final ViewTreeObserver vto = mCoverArt.getViewTreeObserver();
    vto.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
        @Override
        public boolean onPreDraw() {
            if (mCoverHelper != null) {
                mCoverHelper.setCachedCoverMaxSize(mCoverArt.getMeasuredHeight());
            }
            return true;
        }
    });
    mCoverHelper.addCoverDownloadListener(mCoverArtListener);

    ((TextView) headerView.findViewById(R.id.separator_title)).setText(R.string.songs);
    ((ListView) mList).addHeaderView(headerView, null, false);

    mPopupMenu = new PopupMenu(getActivity(), mAlbumMenu);
    mPopupMenu.getMenu().add(Menu.NONE, ADD, Menu.NONE, R.string.addAlbum);
    mPopupMenu.getMenu().add(Menu.NONE, ADD_REPLACE, Menu.NONE, R.string.addAndReplace);
    mPopupMenu.getMenu().add(Menu.NONE, ADD_REPLACE_PLAY, Menu.NONE, R.string.addAndReplacePlay);
    mPopupMenu.getMenu().add(Menu.NONE, ADD_PLAY, Menu.NONE, R.string.addAndPlay);
    mPopupMenu.getMenu().add(Menu.NONE, GOTO_ARTIST, Menu.NONE, R.string.goToArtist);

    mPopupMenu.setOnMenuItemClickListener(new OnMenuItemClickListener() {

        @Override
        public boolean onMenuItemClick(final MenuItem item) {
            final int itemId = item.getItemId();
            if (itemId == GOTO_ARTIST) {
                final Intent intent = new Intent(getActivity(), SimpleLibraryActivity.class);
                intent.putExtra("artist", mAlbum.getArtist());
                startActivityForResult(intent, -1);
            } else {
                mApp.oMPDAsyncHelper.execAsync(new Runnable() {
                    @Override
                    public void run() {
                        boolean replace = false;
                        boolean play = false;
                        switch (itemId) {
                        case ADD_REPLACE_PLAY:
                            replace = true;
                            play = true;
                            break;
                        case ADD_REPLACE:
                            replace = true;
                            break;
                        case ADD_PLAY:
                            play = true;
                            break;
                        default:
                            break;
                        }
                        try {
                            mApp.oMPDAsyncHelper.oMPD.add(mAlbum, replace, play);
                            Tools.notifyUser(R.string.albumAdded, mAlbum);
                        } catch (final IOException | MPDException e) {
                            Log.e(TAG, "Failed to add, replace, play.", e);
                        }
                    }
                });
            }
            return true;
        }
    });

    mAlbumMenu.setOnTouchListener(PopupMenuCompat.getDragToOpenListener(mPopupMenu));
    mAlbumMenu.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(final View v) {
            mPopupMenu.show();
        }
    });

    mCoverPopupMenu = new PopupMenu(getActivity(), mCoverArt);
    mCoverPopupMenu.getMenu().add(POPUP_COVER_BLACKLIST, POPUP_COVER_BLACKLIST, 0, R.string.otherCover);
    mCoverPopupMenu.getMenu().add(POPUP_COVER_SELECTIVE_CLEAN, POPUP_COVER_SELECTIVE_CLEAN, 0,
            R.string.resetCover);
    mCoverPopupMenu.setOnMenuItemClickListener(new OnMenuItemClickListener() {

        @Override
        public boolean onMenuItemClick(final MenuItem item) {
            final int groupId = item.getGroupId();
            boolean result = true;

            if (groupId == POPUP_COVER_BLACKLIST) {
                final AlbumInfo albumInfo = new AlbumInfo(mAlbum);

                CoverManager.getInstance().markWrongCover(albumInfo);
                updateCover(albumInfo);
                updateNowPlayingSmallFragment(albumInfo);
            } else if (groupId == POPUP_COVER_SELECTIVE_CLEAN) {
                final AlbumInfo albumInfo = new AlbumInfo(mAlbum);

                CoverManager.getInstance().clear(albumInfo);
                updateCover(albumInfo);
                updateNowPlayingSmallFragment(albumInfo);
            } else {
                result = false;
            }

            return result;
        }
    });

    mCoverArt.setOnLongClickListener(new View.OnLongClickListener() {
        @Override
        public boolean onLongClick(final View v) {
            mCoverPopupMenu.show();
            return false;
        }
    });

    updateFromItems();

    return view;
}

From source file:com.amagi82.kerbalspaceapp.MissionPlanner.java

/**
 * This method animates all other views in the ListView container (not including ignoreView) into their final positions. It is called
 * after ignoreView has been removed from the adapter, but before layout has been run. The approach here is to figure out where
 * everything is now, then allow layout to run, then figure out where everything is after layout, and then to run animations between all
 * of those start/end positions.//from w ww  .  ja  v a2 s. co m
 */
private void animateRemoval(final ListView listview, View viewToRemove) {
    int firstVisiblePosition = listview.getFirstVisiblePosition();
    for (int i = 0; i < listview.getChildCount(); ++i) {
        View child = listview.getChildAt(i);
        if (child != viewToRemove) {
            int position = firstVisiblePosition + i;
            long itemId = mAdapter.getItemId(position);
            mItemIdTopMap.put(itemId, child.getTop());
        }
    }
    // Delete the item from the adapter
    int position = mListView.getPositionForView(viewToRemove);
    mAdapter.remove(mAdapter.getItem(position));
    mAdapter.notifyDataSetChanged();
    refreshDeltaV();

    final ViewTreeObserver observer = listview.getViewTreeObserver();
    observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
        @Override
        public boolean onPreDraw() {
            observer.removeOnPreDrawListener(this);
            boolean firstAnimation = true;
            int firstVisiblePosition = listview.getFirstVisiblePosition();
            for (int i = 0; i < listview.getChildCount(); ++i) {
                final View child = listview.getChildAt(i);
                int position = firstVisiblePosition + i;
                long itemId = mAdapter.getItemId(position);
                Integer startTop = mItemIdTopMap.get(itemId);
                int top = child.getTop();
                if (startTop != null) {
                    if (startTop != top) {
                        int delta = startTop - top;
                        child.setTranslationY(delta);
                        child.animate().setDuration(MOVE_DURATION).translationY(0);
                        if (firstAnimation) {
                            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
                                child.animate().setListener(new AnimatorListenerAdapter() {
                                    @Override
                                    public void onAnimationEnd(Animator animation) {
                                        mBackgroundContainer.hideBackground();
                                        mSwiping = false;
                                        mListView.setEnabled(true);

                                    }
                                });
                            } else {
                                child.animate().withEndAction(new Runnable() {
                                    @Override
                                    public void run() {
                                        mBackgroundContainer.hideBackground();
                                        mSwiping = false;
                                        mListView.setEnabled(true);
                                    }
                                });
                                firstAnimation = false;
                            }
                        }
                    }
                } else {
                    // Animate new views along with the others. The catch is that they did not
                    // exist in the start state, so we must calculate their starting position
                    // based on neighboring views.
                    int childHeight = child.getHeight() + listview.getDividerHeight();
                    startTop = top + (i > 0 ? childHeight : -childHeight);
                    int delta = startTop - top;
                    child.setTranslationY(delta);
                    child.animate().setDuration(MOVE_DURATION).translationY(0);
                    if (firstAnimation) {
                        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
                            child.animate().setListener(new AnimatorListenerAdapter() {
                                @Override
                                public void onAnimationEnd(Animator animation) {
                                    mBackgroundContainer.hideBackground();
                                    mSwiping = false;
                                    mListView.setEnabled(true);

                                }
                            });
                        } else {
                            child.animate().withEndAction(new Runnable() {
                                @Override
                                public void run() {
                                    mBackgroundContainer.hideBackground();
                                    mSwiping = false;
                                    mListView.setEnabled(true);
                                }
                            });
                            firstAnimation = false;
                        }
                    }
                }
            }
            mItemIdTopMap.clear();
            return true;
        }
    });

}

From source file:fr.tvbarthel.apps.simpleweatherforcast.MainActivity.java

private void initRootPadding() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
        final Resources resources = getResources();
        final boolean isPortrait = resources.getBoolean(R.bool.is_portrait);
        final ActionBar actionBar = getSupportActionBar();

        final ViewTreeObserver vto = mRootView.getViewTreeObserver();
        if (vto.isAlive()) {
            vto.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
                @Override// w w w  .j  a v a 2  s .  c o  m
                public boolean onPreDraw() {
                    mRootView.getViewTreeObserver().removeOnPreDrawListener(this);

                    int paddingBottom = mRootView.getPaddingBottom();
                    int paddingTop = mRootView.getPaddingTop();
                    int paddingRight = mRootView.getPaddingRight();
                    int paddingLeft = mRootView.getPaddingLeft();

                    // Add the status bar height to the top padding.
                    int resourceId = resources.getIdentifier("status_bar_height", "dimen", "android");
                    if (resourceId > 0) {
                        paddingTop += resources.getDimensionPixelSize(resourceId);
                    }

                    if (isPortrait) {
                        // Add the navigation bar height to the bottom padding.
                        resourceId = resources.getIdentifier("navigation_bar_height", "dimen", "android");
                        if (resourceId > 0) {
                            paddingBottom += resources.getDimensionPixelSize(resourceId);
                        }
                    } else {
                        // Add the navigation bar width to the right padding.
                        resourceId = resources.getIdentifier("navigation_bar_width", "dimen", "android");
                        if (resourceId > 0) {
                            paddingRight += resources.getDimensionPixelSize(resourceId);
                        }
                    }

                    mRootView.setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom);
                    return true;
                }
            });
        }
    }
}

From source file:com.dgnt.dominionCardPicker.view.DynamicListView.java

/**
 * This method determines whether the hover cell has been shifted far enough
 * to invoke a cell swap. If so, then the respective cell swap candidate is
 * determined and the data set is changed. Upon posting a notification of the
 * data set change, a layout is invoked to place the cells in the right place.
 * Using a ViewTreeObserver and a corresponding OnPreDrawListener, we can
 * offset the cell being swapped to where it previously was and then animate it to
 * its new position./*from   w  w w.j  ava2 s . c om*/
 */
private void handleCellSwitch() {
    final int deltaY = mLastEventY - mDownY;
    int deltaYTotal = mHoverCellOriginalBounds.top + mTotalOffset + deltaY;

    View belowView = getViewForID(mBelowItemId);
    View mobileView = getViewForID(mMobileItemId);
    View aboveView = getViewForID(mAboveItemId);

    boolean isBelow = (belowView != null) && (deltaYTotal > belowView.getTop());
    boolean isAbove = (aboveView != null) && (deltaYTotal < aboveView.getTop());

    if (isBelow || isAbove) {

        final long switchItemID = isBelow ? mBelowItemId : mAboveItemId;
        View switchView = isBelow ? belowView : aboveView;
        final int originalItem = getPositionForView(mobileView);

        if (switchView == null) {
            updateNeighborViewsForID(mMobileItemId);
            return;
        }

        swapElements(list, originalItem, getPositionForView(switchView));

        ((BaseAdapter) getAdapter()).notifyDataSetChanged();

        mDownY = mLastEventY;

        final int switchViewStartTop = switchView.getTop();

        mobileView.setVisibility(View.VISIBLE);
        switchView.setVisibility(View.VISIBLE);

        updateNeighborViewsForID(mMobileItemId);

        final ViewTreeObserver observer = getViewTreeObserver();
        observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
            public boolean onPreDraw() {
                observer.removeOnPreDrawListener(this);

                View switchView = getViewForID(switchItemID);

                mTotalOffset += deltaY;

                int switchViewNewTop = switchView.getTop();
                int delta = switchViewStartTop - switchViewNewTop;

                switchView.setTranslationY(delta);

                ObjectAnimator animator = ObjectAnimator.ofFloat(switchView, View.TRANSLATION_Y, 0);
                animator.setDuration(MOVE_DURATION);
                animator.start();

                return true;
            }
        });
    }
}

From source file:com.modprobe.profit.ExpandingListView.java

/**
 * This method collapses the view that was clicked and animates all the views
 * around it to close around the collapsing view. There are several steps required
 * to do this which are outlined below./*w w  w  . j  av a 2s .  c om*/
 *
 * 1. Update the layout parameters of the view clicked so as to minimize its height
 *    to the original collapsed (default) state.
 * 2. After invoking a layout, the listview will shift all the cells so as to display
 *    them most efficiently. Therefore, during the first predraw pass, the listview
 *    must be offset by some amount such that given the custom bound change upon
 *    collapse, all the cells that need to be on the screen after the layout
 *    are rendered by the listview.
 * 3. On the second predraw pass, all the items are first returned to their original
 *    location (before the first layout).
 * 4. The collapsing view's bounds are animated to what the final values should be.
 * 5. The bounds above the collapsing view are animated downwards while the bounds
 *    below the collapsing view are animated upwards.
 * 6. The extra text is faded out as its contents become visible throughout the
 *    animation process.
 */

private void collapseView(final View view) {
    final SuggestionExpandingListViewItem viewObject = (SuggestionExpandingListViewItem) getItemAtPosition(
            getPositionForView(view));

    /* Store the original top and bottom bounds of all the cells.*/
    final int oldTop = view.getTop();
    final int oldBottom = view.getBottom();

    final HashMap<View, int[]> oldCoordinates = new HashMap<View, int[]>();

    int childCount = getChildCount();
    for (int i = 0; i < childCount; i++) {
        View v = getChildAt(i);
        ViewCompat.setHasTransientState(v, true);
        oldCoordinates.put(v, new int[] { v.getTop(), v.getBottom() });
    }

    /* Update the layout so the extra content becomes invisible.*/
    view.setLayoutParams(new AbsListView.LayoutParams(AbsListView.LayoutParams.MATCH_PARENT,
            viewObject.getCollapsedHeight()));

    /* Add an onPreDraw listener. */
    final ViewTreeObserver observer = getViewTreeObserver();
    observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {

        @Override
        public boolean onPreDraw() {

            if (!mShouldRemoveObserver) {
                /*Same as for expandingView, the parameters for setSelectionFromTop must
                * be determined such that the necessary cells of the ListView are rendered
                * and added to it.*/
                mShouldRemoveObserver = true;

                int newTop = view.getTop();
                int newBottom = view.getBottom();

                int newHeight = newBottom - newTop;
                int oldHeight = oldBottom - oldTop;
                int deltaHeight = oldHeight - newHeight;

                mTranslate = getTopAndBottomTranslations(oldTop, oldBottom, deltaHeight, false);

                int currentTop = view.getTop();
                int futureTop = oldTop + mTranslate[0];

                int firstChildStartTop = getChildAt(0).getTop();
                int firstVisiblePosition = getFirstVisiblePosition();
                int deltaTop = currentTop - futureTop;

                int i;
                int childCount = getChildCount();
                for (i = 0; i < childCount; i++) {
                    View v = getChildAt(i);
                    int height = v.getBottom() - Math.max(0, v.getTop());
                    if (deltaTop - height > 0) {
                        firstVisiblePosition++;
                        deltaTop -= height;
                    } else {
                        break;
                    }
                }

                if (i > 0) {
                    firstChildStartTop = 0;
                }

                setSelectionFromTop(firstVisiblePosition, firstChildStartTop - deltaTop);

                requestLayout();

                return false;
            }

            mShouldRemoveObserver = false;
            observer.removeOnPreDrawListener(this);

            int yTranslateTop = mTranslate[0];
            int yTranslateBottom = mTranslate[1];

            int index = indexOfChild(view);
            int childCount = getChildCount();
            for (int i = 0; i < childCount; i++) {
                View v = getChildAt(i);
                int[] old = oldCoordinates.get(v);
                if (old != null) {
                    /* If the cell was present in the ListView before the collapse and
                    * after the collapse then the bounds are reset to their old values.*/
                    v.setTop(old[0]);
                    v.setBottom(old[1]);
                    ViewCompat.setHasTransientState(v, false);
                } else {
                    /* If the cell is present in the ListView after the collapse but
                     * not before the collapse then the bounds are calculated using
                     * the bottom and top translation of the collapsing cell.*/
                    int delta = i > index ? yTranslateBottom : -yTranslateTop;
                    v.setTop(v.getTop() + delta);
                    v.setBottom(v.getBottom() + delta);
                }
            }

            final View expandingLayout = view.findViewById(R.id.expanding_layout);

            /* Animates all the cells present on the screen after the collapse. */
            ArrayList<Animator> animations = new ArrayList<Animator>();
            for (int i = 0; i < childCount; i++) {
                View v = getChildAt(i);
                if (v != view) {
                    float diff = i > index ? -yTranslateBottom : yTranslateTop;
                    animations.add(getAnimation(v, diff, diff));
                }
            }

            /* Adds animation for collapsing the cell that was clicked. */
            animations.add(getAnimation(view, yTranslateTop, -yTranslateBottom));

            /* Adds an animation for fading out the extra content. */
            animations.add(ObjectAnimator.ofFloat(expandingLayout, View.ALPHA, 1, 0));

            /* Disabled the ListView for the duration of the animation.*/
            setEnabled(false);
            setClickable(false);

            /* Play all the animations created above together at the same time. */
            AnimatorSet s = new AnimatorSet();
            s.playTogether(animations);
            s.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    expandingLayout.setVisibility(View.GONE);
                    view.setLayoutParams(new AbsListView.LayoutParams(AbsListView.LayoutParams.MATCH_PARENT,
                            AbsListView.LayoutParams.WRAP_CONTENT));
                    viewObject.setExpanded(false);
                    setEnabled(true);
                    setClickable(true);
                    /* Note that alpha must be set back to 1 in case this view is reused
                    * by a cell that was expanded, but not yet collapsed, so its state
                    * should persist in an expanded state with the extra content visible.*/
                    expandingLayout.setAlpha(1);
                }
            });
            s.start();

            return true;
        }
    });
}

From source file:com.modprobe.profit.ExpandingListView.java

/**
 * This method expands the view that was clicked and animates all the views
 * around it to make room for the expanding view. There are several steps required
 * to do this which are outlined below.//  w ww .j a v  a2 s . c  o m
 *
 * 1. Store the current top and bottom bounds of each visible item in the listview.
 * 2. Update the layout parameters of the selected view. In the context of this
 *    method, the view should be originally collapsed and set to some custom height.
 *    The layout parameters are updated so as to wrap the content of the additional
 *    text that is to be displayed.
 *
 * After invoking a layout to take place, the listview will order all the items
 * such that there is space for each view. This layout will be independent of what
 * the bounds of the items were prior to the layout so two pre-draw passes will
 * be made. This is necessary because after the layout takes place, some views that
 * were visible before the layout may now be off bounds but a reference to these
 * views is required so the animation completes as intended.
 *
 * 3. The first predraw pass will set the bounds of all the visible items to
 *    their original location before the layout took place and then force another
 *    layout. Since the bounds of the cells cannot be set directly, the method
 *    setSelectionFromTop can be used to achieve a very similar effect.
 * 4. The expanding view's bounds are animated to what the final values should be
 *    from the original bounds.
 * 5. The bounds above the expanding view are animated upwards while the bounds
 *    below the expanding view are animated downwards.
 * 6. The extra text is faded in as its contents become visible throughout the
 *    animation process.
 *
 * It is important to note that the listview is disabled during the animation
 * because the scrolling behaviour is unpredictable if the bounds of the items
 * within the listview are not constant during the scroll.
 */

private void expandView(final View view) {
    final SuggestionExpandingListViewItem viewObject = (SuggestionExpandingListViewItem) getItemAtPosition(
            getPositionForView(view));

    /* Store the original top and bottom bounds of all the cells.*/
    final int oldTop = view.getTop();
    final int oldBottom = view.getBottom();

    final HashMap<View, int[]> oldCoordinates = new HashMap<View, int[]>();

    int childCount = getChildCount();
    for (int i = 0; i < childCount; i++) {
        View v = getChildAt(i);
        ViewCompat.setHasTransientState(v, true);
        oldCoordinates.put(v, new int[] { v.getTop(), v.getBottom() });
    }

    /* Update the layout so the extra content becomes visible.*/
    final View expandingLayout = view.findViewById(R.id.expanding_layout);
    expandingLayout.setVisibility(View.VISIBLE);

    /* Add an onPreDraw Listener to the listview. onPreDraw will get invoked after onLayout
    * and onMeasure have run but before anything has been drawn. This
    * means that the final post layout properties for all the items have already been
    * determined, but still have not been rendered onto the screen.*/
    final ViewTreeObserver observer = getViewTreeObserver();
    observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {

        @Override
        public boolean onPreDraw() {
            /* Determine if this is the first or second pass.*/
            if (!mShouldRemoveObserver) {
                mShouldRemoveObserver = true;

                /* Calculate what the parameters should be for setSelectionFromTop.
                * The ListView must be offset in a way, such that after the animation
                * takes place, all the cells that remain visible are rendered completely
                * by the ListView.*/
                int newTop = view.getTop();
                int newBottom = view.getBottom();

                int newHeight = newBottom - newTop;
                int oldHeight = oldBottom - oldTop;
                int delta = newHeight - oldHeight;

                mTranslate = getTopAndBottomTranslations(oldTop, oldBottom, delta, true);

                int currentTop = view.getTop();
                int futureTop = oldTop - mTranslate[0];

                int firstChildStartTop = getChildAt(0).getTop();
                int firstVisiblePosition = getFirstVisiblePosition();
                int deltaTop = currentTop - futureTop;

                int i;
                int childCount = getChildCount();
                for (i = 0; i < childCount; i++) {
                    View v = getChildAt(i);
                    int height = v.getBottom() - Math.max(0, v.getTop());
                    if (deltaTop - height > 0) {
                        firstVisiblePosition++;
                        deltaTop -= height;
                    } else {
                        break;
                    }
                }

                if (i > 0) {
                    firstChildStartTop = 0;
                }

                setSelectionFromTop(firstVisiblePosition, firstChildStartTop - deltaTop);

                /* Request another layout to update the layout parameters of the cells.*/
                requestLayout();

                /* Return false such that the ListView does not redraw its contents on
                 * this layout but only updates all the parameters associated with its
                 * children.*/
                return false;
            }

            /* Remove the predraw listener so this method does not keep getting called. */
            mShouldRemoveObserver = false;
            observer.removeOnPreDrawListener(this);

            int yTranslateTop = mTranslate[0];
            int yTranslateBottom = mTranslate[1];

            ArrayList<Animator> animations = new ArrayList<Animator>();

            int index = indexOfChild(view);

            /* Loop through all the views that were on the screen before the cell was
            *  expanded. Some cells will still be children of the ListView while
            *  others will not. The cells that remain children of the ListView
            *  simply have their bounds animated appropriately. The cells that are no
            *  longer children of the ListView also have their bounds animated, but
            *  must also be added to a list of views which will be drawn in dispatchDraw.*/
            for (View v : oldCoordinates.keySet()) {
                int[] old = oldCoordinates.get(v);
                v.setTop(old[0]);
                v.setBottom(old[1]);
                if (v.getParent() == null) {
                    mViewsToDraw.add(v);
                    int delta = old[0] < oldTop ? -yTranslateTop : yTranslateBottom;
                    animations.add(getAnimation(v, delta, delta));
                } else {
                    int i = indexOfChild(v);
                    if (v != view) {
                        int delta = i > index ? yTranslateBottom : -yTranslateTop;
                        animations.add(getAnimation(v, delta, delta));
                    }
                    ViewCompat.setHasTransientState(v, false);
                }
            }

            /* Adds animation for expanding the cell that was clicked. */
            animations.add(getAnimation(view, -yTranslateTop, yTranslateBottom));

            /* Adds an animation for fading in the extra content. */
            animations.add(ObjectAnimator.ofFloat(view.findViewById(R.id.expanding_layout), View.ALPHA, 0, 1));

            /* Disabled the ListView for the duration of the animation.*/
            setEnabled(false);
            setClickable(false);

            /* Play all the animations created above together at the same time. */
            AnimatorSet s = new AnimatorSet();
            s.playTogether(animations);
            s.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    viewObject.setExpanded(true);
                    setEnabled(true);
                    setClickable(true);
                    if (mViewsToDraw.size() > 0) {
                        for (View v : mViewsToDraw) {
                            ViewCompat.setHasTransientState(v, false);
                        }
                    }
                    mViewsToDraw.clear();
                }
            });
            s.start();
            return true;
        }
    });
}

From source file:com.shoshin.paidpay.ExpandingListView.java

/**
 * This method collapses the view that was clicked and animates all the views
 * around it to close around the collapsing view. There are several steps required
 * to do this which are outlined below.//from w ww.  j  a  v a 2 s.c om
 *
 * 1. Update the layout parameters of the view clicked so as to minimize its height
 *    to the original collapsed (default) state.
 * 2. After invoking a layout, the listview will shift all the cells so as to display
 *    them most efficiently. Therefore, during the first predraw pass, the listview
 *    must be offset by some amount such that given the custom bound change upon
 *    collapse, all the cells that need to be on the screen after the layout
 *    are rendered by the listview.
 * 3. On the second predraw pass, all the items are first returned to their original
 *    location (before the first layout).
 * 4. The collapsing view's bounds are animated to what the final values should be.
 * 5. The bounds above the collapsing view are animated downwards while the bounds
 *    below the collapsing view are animated upwards.
 * 6. The extra text is faded out as its contents become visible throughout the
 *    animation process.
 */

private void collapseView(final View view) {
    final ExpandableListItem viewObject = (ExpandableListItem) getItemAtPosition(getPositionForView(view));

    /* Store the original top and bottom bounds of all the cells.*/
    final int oldTop = view.getTop();
    final int oldBottom = view.getBottom();

    final HashMap<View, int[]> oldCoordinates = new HashMap<View, int[]>();

    int childCount = getChildCount();
    for (int i = 0; i < childCount; i++) {
        View v = getChildAt(i);
        ViewCompat.setHasTransientState(v, true);
        oldCoordinates.put(v, new int[] { v.getTop(), v.getBottom() });
    }

    /* Update the layout so the extra content becomes invisible.*/
    view.setLayoutParams(new AbsListView.LayoutParams(AbsListView.LayoutParams.MATCH_PARENT,
            viewObject.getCollapsedHeight()));

    /* Add an onPreDraw listener. */
    final ViewTreeObserver observer = getViewTreeObserver();
    observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {

        @Override
        public boolean onPreDraw() {

            if (!mShouldRemoveObserver) {
                /*Same as for expandingView, the parameters for setSelectionFromTop must
                * be determined such that the necessary cells of the ListView are rendered
                * and added to it.*/
                mShouldRemoveObserver = true;

                int newTop = view.getTop();
                int newBottom = view.getBottom();

                int newHeight = newBottom - newTop;
                int oldHeight = oldBottom - oldTop;
                int deltaHeight = oldHeight - newHeight;

                mTranslate = getTopAndBottomTranslations(oldTop, oldBottom, deltaHeight, false);

                int currentTop = view.getTop();
                int futureTop = oldTop + mTranslate[0];

                int firstChildStartTop = getChildAt(0).getTop();
                int firstVisiblePosition = getFirstVisiblePosition();
                int deltaTop = currentTop - futureTop;

                int i;
                int childCount = getChildCount();
                for (i = 0; i < childCount; i++) {
                    View v = getChildAt(i);
                    int height = v.getBottom() - Math.max(0, v.getTop());
                    if (deltaTop - height > 0) {
                        firstVisiblePosition++;
                        deltaTop -= height;
                    } else {
                        break;
                    }
                }

                if (i > 0) {
                    firstChildStartTop = 0;
                }

                setSelectionFromTop(firstVisiblePosition, firstChildStartTop - deltaTop);

                requestLayout();

                return false;
            }

            mShouldRemoveObserver = false;
            observer.removeOnPreDrawListener(this);

            int yTranslateTop = mTranslate[0];
            int yTranslateBottom = mTranslate[1];

            int index = indexOfChild(view);
            int childCount = getChildCount();
            for (int i = 0; i < childCount; i++) {
                View v = getChildAt(i);
                int[] old = oldCoordinates.get(v);
                if (old != null) {
                    /* If the cell was present in the ListView before the collapse and
                    * after the collapse then the bounds are reset to their old values.*/
                    v.setTop(old[0]);
                    v.setBottom(old[1]);
                    ViewCompat.setHasTransientState(v, false);
                } else {
                    /* If the cell is present in the ListView after the collapse but
                     * not before the collapse then the bounds are calculated using
                     * the bottom and top translation of the collapsing cell.*/
                    int delta = i > index ? yTranslateBottom : -yTranslateTop;
                    v.setTop(v.getTop() + delta);
                    v.setBottom(v.getBottom() + delta);
                }
            }

            final View expandingLayout = view.findViewById(R.id.expanding_layout);

            /* Animates all the cells present on the screen after the collapse. */
            ArrayList<Animator> animations = new ArrayList<Animator>();
            for (int i = 0; i < childCount; i++) {
                View v = getChildAt(i);
                if (v != view) {
                    float diff = i > index ? -yTranslateBottom : yTranslateTop;
                    animations.add(getAnimation(v, diff, diff));
                }
            }

            /* Adds animation for collapsing the cell that was clicked. */
            animations.add(getAnimation(view, yTranslateTop, -yTranslateBottom));

            /* Adds an animation for fading out the extra content. */
            //TODO
            animations.add(ObjectAnimator.ofFloat(expandingLayout, View.ALPHA, 1, 0));

            /* Disabled the ListView for the duration of the animation.*/
            setEnabled(false);
            setClickable(false);

            /* Play all the animations created above together at the same time. */
            AnimatorSet s = new AnimatorSet();
            s.playTogether(animations);
            s.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    expandingLayout.setVisibility(View.GONE);
                    view.setLayoutParams(new AbsListView.LayoutParams(AbsListView.LayoutParams.MATCH_PARENT,
                            AbsListView.LayoutParams.WRAP_CONTENT));
                    viewObject.setExpanded(false);
                    setEnabled(true);
                    setClickable(true);
                    /* Note that alpha must be set back to 1 in case this view is reused
                    * by a cell that was expanded, but not yet collapsed, so its state
                    * should persist in an expanded state with the extra content visible.*/
                    expandingLayout.setAlpha(1);
                    invalidateViews();
                }
            });
            s.start();

            return true;
        }
    });
}

From source file:com.shoshin.paidpay.ExpandingListView.java

/**
 * This method expands the view that was clicked and animates all the views
 * around it to make room for the expanding view. There are several steps required
 * to do this which are outlined below.//from w  w w.  j a  v  a2  s . com
 *
 * 1. Store the current top and bottom bounds of each visible item in the listview.
 * 2. Update the layout parameters of the selected view. In the context of this
 *    method, the view should be originally collapsed and set to some custom height.
 *    The layout parameters are updated so as to wrap the content of the additional
 *    text that is to be displayed.
 *
 * After invoking a layout to take place, the listview will order all the items
 * such that there is space for each view. This layout will be independent of what
 * the bounds of the items were prior to the layout so two pre-draw passes will
 * be made. This is necessary because after the layout takes place, some views that
 * were visible before the layout may now be off bounds but a reference to these
 * views is required so the animation completes as intended.
 *
 * 3. The first predraw pass will set the bounds of all the visible items to
 *    their original location before the layout took place and then force another
 *    layout. Since the bounds of the cells cannot be set directly, the method
 *    setSelectionFromTop can be used to achieve a very similar effect.
 * 4. The expanding view's bounds are animated to what the final values should be
 *    from the original bounds.
 * 5. The bounds above the expanding view are animated upwards while the bounds
 *    below the expanding view are animated downwards.
 * 6. The extra text is faded in as its contents become visible throughout the
 *    animation process.
 *
 * It is important to note that the listview is disabled during the animation
 * because the scrolling behaviour is unpredictable if the bounds of the items
 * within the listview are not constant during the scroll.
 */

private void expandView(final View view) {
    final ExpandableListItem viewObject = (ExpandableListItem) getItemAtPosition(getPositionForView(view));

    /* Store the original top and bottom bounds of all the cells.*/
    final int oldTop = view.getTop();
    final int oldBottom = view.getBottom();

    final HashMap<View, int[]> oldCoordinates = new HashMap<View, int[]>();

    int childCount = getChildCount();
    for (int i = 0; i < childCount; i++) {
        View v = getChildAt(i);
        ViewCompat.setHasTransientState(v, true);
        oldCoordinates.put(v, new int[] { v.getTop(), v.getBottom() });
    }

    /* Update the layout so the extra content becomes visible.*/
    final View expandingLayout = view.findViewById(R.id.expanding_layout);
    expandingLayout.setVisibility(View.VISIBLE);

    /* Add an onPreDraw Listener to the listview. onPreDraw will get invoked after onLayout
    * and onMeasure have run but before anything has been drawn. This
    * means that the final post layout properties for all the items have already been
    * determined, but still have not been rendered onto the screen.*/
    final ViewTreeObserver observer = getViewTreeObserver();
    observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {

        @Override
        public boolean onPreDraw() {
            /* Determine if this is the first or second pass.*/
            if (!mShouldRemoveObserver) {
                mShouldRemoveObserver = true;

                /* Calculate what the parameters should be for setSelectionFromTop.
                * The ListView must be offset in a way, such that after the animation
                * takes place, all the cells that remain visible are rendered completely
                * by the ListView.*/
                int newTop = view.getTop();
                int newBottom = view.getBottom();

                int newHeight = newBottom - newTop;
                int oldHeight = oldBottom - oldTop;
                int delta = newHeight - oldHeight;

                mTranslate = getTopAndBottomTranslations(oldTop, oldBottom, delta, true);

                int currentTop = view.getTop();
                int futureTop = oldTop - mTranslate[0];

                int firstChildStartTop = getChildAt(0).getTop();
                int firstVisiblePosition = getFirstVisiblePosition();
                int deltaTop = currentTop - futureTop;

                int i;
                int childCount = getChildCount();
                for (i = 0; i < childCount; i++) {
                    View v = getChildAt(i);
                    int height = v.getBottom() - Math.max(0, v.getTop());
                    if (deltaTop - height > 0) {
                        firstVisiblePosition++;
                        deltaTop -= height;
                    } else {
                        break;
                    }
                }

                if (i > 0) {
                    firstChildStartTop = 0;
                }

                setSelectionFromTop(firstVisiblePosition, firstChildStartTop - deltaTop);

                /* Request another layout to update the layout parameters of the cells.*/
                requestLayout();

                /* Return false such that the ListView does not redraw its contents on
                 * this layout but only updates all the parameters associated with its
                 * children.*/
                return false;
            }

            /* Remove the predraw listener so this method does not keep getting called. */
            mShouldRemoveObserver = false;
            observer.removeOnPreDrawListener(this);

            int yTranslateTop = mTranslate[0];
            int yTranslateBottom = mTranslate[1];

            ArrayList<Animator> animations = new ArrayList<Animator>();

            int index = indexOfChild(view);

            /* Loop through all the views that were on the screen before the cell was
            *  expanded. Some cells will still be children of the ListView while
            *  others will not. The cells that remain children of the ListView
            *  simply have their bounds animated appropriately. The cells that are no
            *  longer children of the ListView also have their bounds animated, but
            *  must also be added to a list of views which will be drawn in dispatchDraw.*/
            for (View v : oldCoordinates.keySet()) {
                int[] old = oldCoordinates.get(v);
                v.setTop(old[0]);
                v.setBottom(old[1]);
                if (v.getParent() == null) {
                    mViewsToDraw.add(v);
                    int delta = old[0] < oldTop ? -yTranslateTop : yTranslateBottom;
                    animations.add(getAnimation(v, delta, delta));
                } else {
                    int i = indexOfChild(v);
                    if (v != view) {
                        int delta = i > index ? yTranslateBottom : -yTranslateTop;
                        animations.add(getAnimation(v, delta, delta));
                    }
                    ViewCompat.setHasTransientState(v, false);
                }
            }

            /* Adds animation for expanding the cell that was clicked. */
            animations.add(getAnimation(view, -yTranslateTop, yTranslateBottom));

            /* Adds an animation for fading in the extra content. */
            //TODO
            animations.add(ObjectAnimator.ofFloat(view.findViewById(R.id.expanding_layout), View.ALPHA, 0, 1));

            /* Disabled the ListView for the duration of the animation.*/
            setEnabled(false);
            setClickable(false);

            /* Play all the animations created above together at the same time. */
            AnimatorSet s = new AnimatorSet();
            s.playTogether(animations);
            s.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    viewObject.setExpanded(true);
                    setEnabled(true);
                    setClickable(true);
                    if (mViewsToDraw.size() > 0) {
                        for (View v : mViewsToDraw) {
                            ViewCompat.setHasTransientState(v, false);
                        }
                    }
                    mViewsToDraw.clear();
                }
            });
            s.start();
            return true;
        }
    });
}

From source file:com.example.customview.DynamicListView.java

/**
 * This method determines whether the hover cell has been shifted far enough
 * to invoke a cell swap. If so, then the respective cell swap candidate is
 * determined and the data set is changed. Upon posting a notification of the
 * data set change, a layout is invoked to place the cells in the right place.
 * Using a ViewTreeObserver and a corresponding OnPreDrawListener, we can
 * offset the cell being swapped to where it previously was and then animate it to
 * its new position.//ww w.  ja  v  a 2 s.c  om
 */
private void handleCellSwitch() {
    final int deltaY = mLastEventY - mDownY;
    int deltaYTotal = mHoverCellOriginalBounds.top + mTotalOffset + deltaY;

    View belowView = getViewForID(mBelowItemId);
    View mobileView = getViewForID(mMobileItemId);
    View aboveView = getViewForID(mAboveItemId);

    boolean isBelow = (belowView != null) && (deltaYTotal > belowView.getTop());
    boolean isAbove = (aboveView != null) && (deltaYTotal < aboveView.getTop());

    if (isBelow || isAbove) {

        final long switchItemID = isBelow ? mBelowItemId : mAboveItemId;
        View switchView = isBelow ? belowView : aboveView;
        final int originalItem = getPositionForView(mobileView);

        if (switchView == null) {
            updateNeighborViewsForID(mMobileItemId);
            return;
        }

        if (getPositionForView(switchView) == mPanelList.size() - 1) {
            return;
        }
        swapElements(mPanelList, originalItem, getPositionForView(switchView));

        ((BaseAdapter) getAdapter()).notifyDataSetChanged();
        mDownY = mLastEventY;

        final int switchViewStartTop = switchView.getTop();

        mobileView.setVisibility(View.VISIBLE);
        switchView.setVisibility(View.INVISIBLE);

        updateNeighborViewsForID(mMobileItemId);

        final ViewTreeObserver observer = getViewTreeObserver();
        observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
            public boolean onPreDraw() {
                observer.removeOnPreDrawListener(this);

                View switchView = getViewForID(switchItemID);

                mTotalOffset += deltaY;

                int switchViewNewTop = switchView.getTop();
                int delta = switchViewStartTop - switchViewNewTop;

                switchView.setTranslationY(delta);

                ObjectAnimator animator = ObjectAnimator.ofFloat(switchView, View.TRANSLATION_Y, 0);
                animator.setDuration(MOVE_DURATION);
                animator.start();

                return true;
            }
        });
    }
}

From source file:com.shoshin.paidpay.ExpandingListViewPayVia.java

/**
 * This method collapses the view that was clicked and animates all the views
 * around it to close around the collapsing view. There are several steps required
 * to do this which are outlined below.//from w  w w  .  ja  va 2  s.  co m
 *
 * 1. Update the layout parameters of the view clicked so as to minimize its height
 *    to the original collapsed (default) state.
 * 2. After invoking a layout, the listview will shift all the cells so as to display
 *    them most efficiently. Therefore, during the first predraw pass, the listview
 *    must be offset by some amount such that given the custom bound change upon
 *    collapse, all the cells that need to be on the screen after the layout
 *    are rendered by the listview.
 * 3. On the second predraw pass, all the items are first returned to their original
 *    location (before the first layout).
 * 4. The collapsing view's bounds are animated to what the final values should be.
 * 5. The bounds above the collapsing view are animated downwards while the bounds
 *    below the collapsing view are animated upwards.
 * 6. The extra text is faded out as its contents become visible throughout the
 *    animation process.
 */

private void collapseView(final View view) {
    final ExpandableCardsWithOffers viewObject = (ExpandableCardsWithOffers) getItemAtPosition(
            getPositionForView(view));

    /* Store the original top and bottom bounds of all the cells.*/
    final int oldTop = view.getTop();
    final int oldBottom = view.getBottom();

    final HashMap<View, int[]> oldCoordinates = new HashMap<View, int[]>();

    int childCount = getChildCount();
    for (int i = 0; i < childCount; i++) {
        View v = getChildAt(i);
        ViewCompat.setHasTransientState(v, true);
        oldCoordinates.put(v, new int[] { v.getTop(), v.getBottom() });
    }

    /* Update the layout so the extra content becomes invisible.*/
    view.setLayoutParams(new AbsListView.LayoutParams(AbsListView.LayoutParams.MATCH_PARENT,
            viewObject.getCollapsedHeight()));

    /* Add an onPreDraw listener. */
    final ViewTreeObserver observer = getViewTreeObserver();
    observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {

        @Override
        public boolean onPreDraw() {

            if (!mShouldRemoveObserver) {
                /*Same as for expandingView, the parameters for setSelectionFromTop must
                * be determined such that the necessary cells of the ListView are rendered
                * and added to it.*/
                mShouldRemoveObserver = true;

                int newTop = view.getTop();
                int newBottom = view.getBottom();

                int newHeight = newBottom - newTop;
                int oldHeight = oldBottom - oldTop;
                int deltaHeight = oldHeight - newHeight;

                mTranslate = getTopAndBottomTranslations(oldTop, oldBottom, deltaHeight, false);

                int currentTop = view.getTop();
                int futureTop = oldTop + mTranslate[0];

                int firstChildStartTop = getChildAt(0).getTop();
                int firstVisiblePosition = getFirstVisiblePosition();
                int deltaTop = currentTop - futureTop;

                int i;
                int childCount = getChildCount();
                for (i = 0; i < childCount; i++) {
                    View v = getChildAt(i);
                    int height = v.getBottom() - Math.max(0, v.getTop());
                    if (deltaTop - height > 0) {
                        firstVisiblePosition++;
                        deltaTop -= height;
                    } else {
                        break;
                    }
                }

                if (i > 0) {
                    firstChildStartTop = 0;
                }

                setSelectionFromTop(firstVisiblePosition, firstChildStartTop - deltaTop);

                requestLayout();

                return false;
            }

            mShouldRemoveObserver = false;
            observer.removeOnPreDrawListener(this);

            int yTranslateTop = mTranslate[0];
            int yTranslateBottom = mTranslate[1];

            int index = indexOfChild(view);
            int childCount = getChildCount();
            for (int i = 0; i < childCount; i++) {
                View v = getChildAt(i);
                int[] old = oldCoordinates.get(v);
                if (old != null) {
                    /* If the cell was present in the ListView before the collapse and
                    * after the collapse then the bounds are reset to their old values.*/
                    v.setTop(old[0]);
                    v.setBottom(old[1]);
                    ViewCompat.setHasTransientState(v, false);
                } else {
                    /* If the cell is present in the ListView after the collapse but
                     * not before the collapse then the bounds are calculated using
                     * the bottom and top translation of the collapsing cell.*/
                    int delta = i > index ? yTranslateBottom : -yTranslateTop;
                    v.setTop(v.getTop() + delta);
                    v.setBottom(v.getBottom() + delta);
                }
            }

            final View expandingLayout = view.findViewById(R.id.expanding_layout);

            /* Animates all the cells present on the screen after the collapse. */
            ArrayList<Animator> animations = new ArrayList<Animator>();
            for (int i = 0; i < childCount; i++) {
                View v = getChildAt(i);
                if (v != view) {
                    float diff = i > index ? -yTranslateBottom : yTranslateTop;
                    animations.add(getAnimation(v, diff, diff));
                }
            }

            /* Adds animation for collapsing the cell that was clicked. */
            animations.add(getAnimation(view, yTranslateTop, -yTranslateBottom));

            /* Adds an animation for fading out the extra content. */
            //TODO
            animations.add(ObjectAnimator.ofFloat(expandingLayout, View.ALPHA, 1, 0));

            /* Disabled the ListView for the duration of the animation.*/
            setEnabled(false);
            setClickable(false);

            /* Play all the animations created above together at the same time. */
            AnimatorSet s = new AnimatorSet();
            s.playTogether(animations);
            s.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    expandingLayout.setVisibility(View.GONE);
                    view.setLayoutParams(new AbsListView.LayoutParams(AbsListView.LayoutParams.MATCH_PARENT,
                            AbsListView.LayoutParams.WRAP_CONTENT));
                    viewObject.setExpanded(false);
                    setEnabled(true);
                    setClickable(true);
                    /* Note that alpha must be set back to 1 in case this view is reused
                    * by a cell that was expanded, but not yet collapsed, so its state
                    * should persist in an expanded state with the extra content visible.*/
                    expandingLayout.setAlpha(1);
                    invalidateViews();
                }
            });
            s.start();

            return true;
        }
    });
}