List of usage examples for android.view View getParent
public final ViewParent getParent()
From source file:self.philbrown.droidQuery.$.java
/** * Adds an Image over each selected View as a mask. * In most cases, this mask can be retrieved by querying siblings. For example: * <pre>/*from w ww. j av a2 s. c o m*/ * ImageView mask = (ImageView) $.with(myView).parent().selectChildren().selectImages().view(0); * </pre> * @param mask the bitmap to draw * @return this */ public $ mask(Bitmap mask) { for (View v : views) { ImageView image = new ImageView(context); image.setImageBitmap(mask); image.setScaleType(ScaleType.FIT_XY); ViewParent parent = v.getParent(); if (parent != null && parent instanceof ViewGroup) { image.setLayoutParams(v.getLayoutParams()); ((ViewGroup) parent).addView(image); } else if (v instanceof ViewGroup) { image.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); ((ViewGroup) v).addView(image); } } return this; }
From source file:self.philbrown.droidQuery.$.java
/** * Adds an Image over each selected View as a mask. * In most cases, this mask can be retrieved by querying siblings. For example: * <pre>// w w w .java 2 s . co m * ImageView mask = (ImageView) $.with(myView).parent().selectChildren().selectImages().view(0); * </pre> * @param mask the drawable to draw * @return this */ public $ mask(Drawable mask) { for (View v : views) { ImageView image = new ImageView(context); image.setImageDrawable(mask); image.setScaleType(ScaleType.FIT_XY); ViewParent parent = v.getParent(); if (parent != null && parent instanceof ViewGroup) { image.setLayoutParams(v.getLayoutParams()); ((ViewGroup) parent).addView(image); } else if (v instanceof ViewGroup) { image.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); ((ViewGroup) v).addView(image); } } return this; }
From source file:self.philbrown.droidQuery.$.java
/** * Adds an Image over each selected View as a mask. * In most cases, this mask can be retrieved by querying siblings. For example: * <pre>//w w w . j a v a 2s.c o m * ImageView mask = (ImageView) $.with(myView).parent().selectChildren().selectImages().view(0); * </pre> * @param resourceId the resource ID of the mask drawable * @return this */ public $ mask(int resourceId) { for (View v : views) { ImageView image = new ImageView(context); image.setImageResource(resourceId); image.setScaleType(ScaleType.FIT_XY); ViewParent parent = v.getParent(); if (parent != null && parent instanceof ViewGroup) { image.setLayoutParams(v.getLayoutParams()); ((ViewGroup) parent).addView(image); } else if (v instanceof ViewGroup) { image.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); ((ViewGroup) v).addView(image); } } return this; }
From source file:com.jforce.chapelhillnextbus.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. * <p/>// ww w .j a va 2s . 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. * <p/> * 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. * <p/> * 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. * <p/> * 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. */ 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.android.launcher3.Workspace.java
void startDrag(CellLayout.CellInfo cellInfo) { View child = cellInfo.cell; // Make sure the drag was started by a long press as opposed to a long click. if (!child.isInTouchMode()) { return;//from w w w . j a va2s . c o m } mDragInfo = cellInfo; child.setVisibility(INVISIBLE); CellLayout layout = (CellLayout) child.getParent().getParent(); layout.prepareChildForDrag(child); beginDragShared(child, this); }
From source file:com.example.android.expandingcells.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 www. jav 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 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); if (expandingLayout == null) { throw new IllegalStateException("Layout must have a ExpandingLayout called 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 = getExpandingTopAndBottomTranslations(getPositionForView(view), oldTop, oldBottom, delta); 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); handleSetTopAndBottom(v, old[0], old[1]); if (v == view) { continue; } else if (v.getParent() == null) { mViewsToDraw.add(v); int delta = old[0] < oldTop ? -yTranslateTop : yTranslateBottom; animations.add(getAnimation(v, old[0], old[1], delta, delta)); } else { int i = indexOfChild(v); if (v != view) { int delta = i > index ? yTranslateBottom : -yTranslateTop; animations.add(getAnimation(v, old[0], old[1], delta, delta)); } ViewCompat.setHasTransientState(v, false); } } /* Adds animation for expanding the cell that was clicked. */ int[] old = oldCoordinates.get(view); animations.add(getAnimation(view, old[0], old[1], -yTranslateTop, yTranslateBottom)); /* Adds an animation for fading in the extra content. */ animations.add(ObjectAnimator.ofFloat(view.findViewById(R.id.expanding_layout), "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(); if (mOnExpandingListener != null) { mOnExpandingListener.onExpanded(view); } } }); s.start(); return true; } }); }
From source file:self.philbrown.droidQuery.$.java
/** * Selects all views within the given current selection that are the single * children of their parent views/*from w w w. java 2 s .c om*/ * @param v the view whose hierarchy will be checked * @return a list of the found views. */ private List<View> recursivelySelectOnlyChilds(View v) { List<View> list = new ArrayList<View>(); if (v instanceof ViewGroup) { for (int i = 0; i < ((ViewGroup) v).getChildCount(); i++) { list.addAll(recursivelySelectOnlyChilds(((ViewGroup) v).getChildAt(i))); } } if (v.getParent() instanceof ViewGroup && ((ViewGroup) v.getParent()).getChildCount() == 1) list.add(v); return list; }
From source file:self.philbrown.droidQuery.$.java
/** * Adds an Image over each selected View as a mask. * In most cases, this mask can be retrieved by querying siblings. For example: * <pre>/*from w w w . j a va 2s . co m*/ * ImageView mask = (ImageView) $.with(myView).parent().selectChildren().selectImages().view(0); * </pre> * @param source asset path, file path (starting with "file://") or URL to image * @param width specifies the output bitmap width * @param height specifies the output bitmap height * @param error if the given source is a file or asset, this receives a droidQuery wrapping the * current context and the {@code Throwable} error. Otherwise, this will receive an * Ajax error. * @return this * @see AjaxOptions#error(Function) */ public $ mask(String source, int width, int height, Function error) { if (source.startsWith("file://")) { try { BitmapFactory.Options opt = new BitmapFactory.Options(); opt.inPreferredConfig = Bitmap.Config.ARGB_8888; if (width >= 0) opt.outWidth = width; if (height >= 0) opt.outHeight = height; Bitmap bitmap = BitmapFactory.decodeFile(source.substring(6), opt); for (View v : views) { ImageView image = new ImageView(context); image.setImageBitmap(Bitmap.createBitmap(bitmap)); image.setScaleType(ScaleType.FIT_XY); ViewParent parent = v.getParent(); if (parent != null && parent instanceof ViewGroup) { image.setLayoutParams(v.getLayoutParams()); ((ViewGroup) parent).addView(image); } else if (v instanceof ViewGroup) { image.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); ((ViewGroup) v).addView(image); } } } catch (Throwable t) { if (error != null) { error.invoke($.with(context), t); } } } else if (URLUtil.isValidUrl(source)) { AjaxOptions options = new AjaxOptions().url(source).type("GET").dataType("image").context(context) .global(false).success(new Function() { @Override public void invoke($ droidQuery, Object... params) { Bitmap bitmap = (Bitmap) params[0]; for (View v : views) { ImageView image = new ImageView(context); image.setImageBitmap(Bitmap.createBitmap(bitmap)); image.setScaleType(ScaleType.FIT_XY); ViewParent parent = v.getParent(); if (parent != null && parent instanceof ViewGroup) { image.setLayoutParams(v.getLayoutParams()); ((ViewGroup) parent).addView(image); } else if (v instanceof ViewGroup) { image.setLayoutParams( new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); ((ViewGroup) v).addView(image); } } } }); if (error != null) { options.error(error); } if (width >= 0) { options.imageWidth(width); } if (height >= 0) { options.imageHeight(height); } $.ajax(options); } else { try { BitmapFactory.Options opt = new BitmapFactory.Options(); opt.inSampleSize = 1; opt.inPurgeable = true; opt.inInputShareable = false; if (width >= 0) opt.outWidth = width; if (height >= 0) opt.outHeight = height; Bitmap bitmap = BitmapFactory.decodeStream(context.getAssets().open(source), new Rect(0, 0, 0, 0), opt); for (View v : views) { ImageView image = new ImageView(context); image.setImageBitmap(Bitmap.createBitmap(bitmap)); image.setScaleType(ScaleType.FIT_XY); ViewParent parent = v.getParent(); if (parent != null && parent instanceof ViewGroup) { image.setLayoutParams(v.getLayoutParams()); ((ViewGroup) parent).addView(image); } else if (v instanceof ViewGroup) { image.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); ((ViewGroup) v).addView(image); } } } catch (Throwable t) { if (error != null) { error.invoke($.with(context), t); } } } return this; }
From source file:app.umitems.greenclock.widget.sgv.StaggeredGridView.java
/** * Measure and layout all currently visible children. * * @param queryAdapter true to requery the adapter for view data *///ww w . j a v a 2 s. co m final void layoutChildren(boolean queryAdapter) { final int paddingLeft = getPaddingLeft(); final int paddingRight = getPaddingRight(); final int itemMargin = mItemMargin; final int availableWidth = (getWidth() - paddingLeft - paddingRight - itemMargin * (mColCount - 1)); final int colWidth = availableWidth / mColCount; // The availableWidth may not be divisible by mColCount. Keep the // remainder. It will be added to the width of the last view in the row. final int remainder = availableWidth % mColCount; boolean viewsRemovedInLayout = false; // If we're animating out stale views, then we want to defer recycling of views. final boolean deferRecyclingForAnimation = mAnimationOutMode != AnimationOut.NONE; if (!deferRecyclingForAnimation) { final int childCount = getChildCount(); // If the latest data set has fewer data items than mFirstPosition, don't keep any // views on screen, and just let the layout logic below retrieve appropriate views // from the recycler. final int viewsToKeepOnScreen = (mItemCount <= mFirstPosition) ? 0 : mItemCount - mFirstPosition; if (childCount > viewsToKeepOnScreen) { // If there are more views laid out than the number of data items remaining to be // laid out, recycle the extraneous views. recycleViewsInRange(viewsToKeepOnScreen, childCount - 1); viewsRemovedInLayout = true; } } else { mViewsToAnimateOut.clear(); } for (int i = 0; i < getChildCount(); i++) { final int position = mFirstPosition + i; View child = getChildAt(i); final int highestAvailableLayoutPosition = mItemBottoms[getNextColumnDown()]; if (deferRecyclingForAnimation && (position >= mItemCount || highestAvailableLayoutPosition >= getHeight())) { // For the remainder of views on screen, they should not be on screen, so we can // skip layout. Add them to the list of views to animate out. // We should only get in this position if deferRecyclingForAnimation = true, // otherwise, we should've recycled all views before getting into this layout loop. mViewsToAnimateOut.add(child); continue; } LayoutParams lp = null; int col = -1; if (child != null) { lp = (LayoutParams) child.getLayoutParams(); col = lp.column; } final boolean needsLayout = queryAdapter || child == null || child.isLayoutRequested(); if (queryAdapter) { View newView = null; if (deferRecyclingForAnimation) { // If we are deferring recycling for animation, then we don't want to pass the // current child in to obtainView for re-use. obtainView() in this case should // try to find the view belonging to this item on screen, or populate a fresh // one from the recycler. newView = obtainView(position); } else { newView = obtainView(position, child); } // Update layout params since they may have changed lp = (LayoutParams) newView.getLayoutParams(); if (newView != child) { if (child != null && !deferRecyclingForAnimation) { mRecycler.addScrap(child); removeViewInLayout(child); viewsRemovedInLayout = true; } // If this view is already in the layout hierarchy, we can just detach it // from the parent and re-attach it at the correct index. If the view has // already been removed from the layout hierarchy, getParent() == null. if (newView.getParent() == this) { detachViewFromParent(newView); attachViewToParent(newView, i, lp); } else { addViewInLayout(newView, i, lp); } } child = newView; // Since the data has changed, we need to make sure the next child is in the // right column. We choose the next column down (vs. next column up) because we // are filling from the top of the screen downwards as we iterate through // visible children. (We take span into account below.) lp.column = getNextColumnDown(); col = lp.column; } setReorderingArea(lp); final int span = Math.min(mColCount, lp.span); // Given the span, check if there's enough space to put this view at this column. // IMPORTANT Propagate the same logic to {@link #calculateLayoutStartOffsets}. if (span > 1) { if (mIsRtlLayout) { // For RTL layout, if the current column index is less than the span of the // child, then we know that there is not enough room remaining to lay this // child out (e.g., if col == 0, but span == 2, then laying this child down // at column = col would put us out of bound into a negative column index.). // For this scenario, reset the index back to the right-most column, and lay // out the child at this position where we can ensure that we can display as // much of the child as possible. if (col + 1 < span) { col = mColCount - 1; } } else { if (mColCount - col < span) { // If not, reset the col to 0. col = 0; } } lp.column = col; } int widthSize = (colWidth * span + itemMargin * (span - 1)); // If it is rtl, we layout the view from col to col - span + // 1. If it reaches the most left column, i.e. we added the // additional width. So the check it span == col +1 if ((mIsRtlLayout && span == col + 1) || (!mIsRtlLayout && span + col == mColCount)) { widthSize += remainder; } if (needsLayout) { final int widthSpec = MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.EXACTLY); final int heightSpec; if (lp.height == LayoutParams.WRAP_CONTENT) { heightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); } else { heightSpec = MeasureSpec.makeMeasureSpec(lp.height, MeasureSpec.EXACTLY); } child.measure(widthSpec, heightSpec); } // Place the top of this child beneath the last by finding the lowest coordinate across // the columns that this child will span. For LTR layout, we scan across from left to // right, and for RTL layout, we scan from right to left. // TODO: Consolidate this logic with getNextRecordDown() in the future, as that method // already calculates the margins for us. This will keep the implementation consistent // with fillUp() and fillDown(). int childTop = mItemBottoms[col] + mItemMargin; if (span > 1) { int lowest = childTop; for (int spanIndex = 0; spanIndex < span; spanIndex++) { final int index = mIsRtlLayout ? col - spanIndex : col + spanIndex; final int bottom = mItemBottoms[index] + mItemMargin; if (bottom > lowest) { lowest = bottom; } } childTop = lowest; } final int childHeight = child.getMeasuredHeight(); final int childBottom = childTop + childHeight; int childLeft = 0; int childRight = 0; if (mIsRtlLayout) { childRight = (getWidth() - paddingRight) - (mColCount - col - 1) * (colWidth + itemMargin); childLeft = childRight - child.getMeasuredWidth(); } else { childLeft = paddingLeft + col * (colWidth + itemMargin); childRight = childLeft + child.getMeasuredWidth(); } /* Log.v(TAG, "[layoutChildren] height: " + childHeight + " top: " + childTop + " bottom: " + childBottom + " left: " + childLeft + " column: " + col + " position: " + position + " id: " + lp.id); */ child.layout(childLeft, childTop, childRight, childBottom); if (lp.id == mFocusedChildIdToScrollIntoView) { child.requestFocus(); } for (int spanIndex = 0; spanIndex < span; spanIndex++) { final int index = mIsRtlLayout ? col - spanIndex : col + spanIndex; mItemBottoms[index] = childBottom; } // Whether or not LayoutRecords may have already existed for the view at this position // on screen, we'll update it after we lay out to ensure that the LayoutRecord // has the most updated information about the view at this position. We can be assured // that all views before those on screen (views with adapter position < mFirstPosition) // have the correct LayoutRecords because calculateLayoutStartOffsets() would have // set them appropriately. LayoutRecord rec = mLayoutRecords.get(position); if (rec == null) { rec = new LayoutRecord(); mLayoutRecords.put(position, rec); } rec.column = lp.column; rec.height = childHeight; rec.id = lp.id; rec.span = span; } // It appears that removeViewInLayout() does not invalidate. So if we make use of this // method during layout, we should invalidate explicitly. if (viewsRemovedInLayout || deferRecyclingForAnimation) { invalidate(); } }
From source file:com.deepak.myclock.widget.sgv.StaggeredGridView.java
/** * Measure and layout all currently visible children. * * @param queryAdapter true to requery the adapter for view data *///from w w w . j a v a2s . c o m final void layoutChildren(boolean queryAdapter) { final int paddingLeft = getPaddingLeft(); final int paddingRight = getPaddingRight(); final int itemMargin = mItemMargin; final int availableWidth = (getWidth() - paddingLeft - paddingRight - itemMargin * (mColCount - 1)); final int colWidth = availableWidth / mColCount; // The availableWidth may not be divisible by mColCount. Keep the // remainder. It will be added to the width of the last view in the row. final int remainder = availableWidth % mColCount; boolean viewsRemovedInLayout = false; // If we're animating out stale views, then we want to defer recycling of views. final boolean deferRecyclingForAnimation = mAnimationOutMode != SgvAnimationHelper.AnimationOut.NONE; if (!deferRecyclingForAnimation) { final int childCount = getChildCount(); // If the latest data set has fewer data items than mFirstPosition, don't keep any // views on screen, and just let the layout logic below retrieve appropriate views // from the recycler. final int viewsToKeepOnScreen = (mItemCount <= mFirstPosition) ? 0 : mItemCount - mFirstPosition; if (childCount > viewsToKeepOnScreen) { // If there are more views laid out than the number of data items remaining to be // laid out, recycle the extraneous views. recycleViewsInRange(viewsToKeepOnScreen, childCount - 1); viewsRemovedInLayout = true; } } else { mViewsToAnimateOut.clear(); } for (int i = 0; i < getChildCount(); i++) { final int position = mFirstPosition + i; View child = getChildAt(i); final int highestAvailableLayoutPosition = mItemBottoms[getNextColumnDown()]; if (deferRecyclingForAnimation && (position >= mItemCount || highestAvailableLayoutPosition >= getHeight())) { // For the remainder of views on screen, they should not be on screen, so we can // skip layout. Add them to the list of views to animate out. // We should only get in this position if deferRecyclingForAnimation = true, // otherwise, we should've recycled all views before getting into this layout loop. mViewsToAnimateOut.add(child); continue; } LayoutParams lp = null; int col = -1; if (child != null) { lp = (LayoutParams) child.getLayoutParams(); col = lp.column; } final boolean needsLayout = queryAdapter || child == null || child.isLayoutRequested(); if (queryAdapter) { View newView = null; if (deferRecyclingForAnimation) { // If we are deferring recycling for animation, then we don't want to pass the // current child in to obtainView for re-use. obtainView() in this case should // try to find the view belonging to this item on screen, or populate a fresh // one from the recycler. newView = obtainView(position); } else { newView = obtainView(position, child); } // Update layout params since they may have changed lp = (LayoutParams) newView.getLayoutParams(); if (newView != child) { if (child != null && !deferRecyclingForAnimation) { mRecycler.addScrap(child); removeViewInLayout(child); viewsRemovedInLayout = true; } // If this view is already in the layout hierarchy, we can just detach it // from the parent and re-attach it at the correct index. If the view has // already been removed from the layout hierarchy, getParent() == null. if (newView.getParent() == this) { detachViewFromParent(newView); attachViewToParent(newView, i, lp); } else { addViewInLayout(newView, i, lp); } } child = newView; // Since the data has changed, we need to make sure the next child is in the // right column. We choose the next column down (vs. next column up) because we // are filling from the top of the screen downwards as we iterate through // visible children. (We take span into account below.) lp.column = getNextColumnDown(); col = lp.column; } setReorderingArea(lp); final int span = Math.min(mColCount, lp.span); // Given the span, check if there's enough space to put this view at this column. // IMPORTANT Propagate the same logic to {@link #calculateLayoutStartOffsets}. if (span > 1) { if (mIsRtlLayout) { // For RTL layout, if the current column index is less than the span of the // child, then we know that there is not enough room remaining to lay this // child out (e.g., if col == 0, but span == 2, then laying this child down // at column = col would put us out of bound into a negative column index.). // For this scenario, reset the index back to the right-most column, and lay // out the child at this position where we can ensure that we can display as // much of the child as possible. if (col + 1 < span) { col = mColCount - 1; } } else { if (mColCount - col < span) { // If not, reset the col to 0. col = 0; } } lp.column = col; } int widthSize = (colWidth * span + itemMargin * (span - 1)); // If it is rtl, we layout the view from col to col - span + // 1. If it reaches the most left column, i.e. we added the // additional width. So the check it span == col +1 if ((mIsRtlLayout && span == col + 1) || (!mIsRtlLayout && span + col == mColCount)) { widthSize += remainder; } if (needsLayout) { final int widthSpec = MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.EXACTLY); final int heightSpec; if (lp.height == LayoutParams.WRAP_CONTENT) { heightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); } else { heightSpec = MeasureSpec.makeMeasureSpec(lp.height, MeasureSpec.EXACTLY); } child.measure(widthSpec, heightSpec); } // Place the top of this child beneath the last by finding the lowest coordinate across // the columns that this child will span. For LTR layout, we scan across from left to // right, and for RTL layout, we scan from right to left. // TODO: Consolidate this logic with getNextRecordDown() in the future, as that method // already calculates the margins for us. This will keep the implementation consistent // with fillUp() and fillDown(). int childTop = mItemBottoms[col] + mItemMargin; if (span > 1) { int lowest = childTop; for (int spanIndex = 0; spanIndex < span; spanIndex++) { final int index = mIsRtlLayout ? col - spanIndex : col + spanIndex; final int bottom = mItemBottoms[index] + mItemMargin; if (bottom > lowest) { lowest = bottom; } } childTop = lowest; } final int childHeight = child.getMeasuredHeight(); final int childBottom = childTop + childHeight; int childLeft = 0; int childRight = 0; if (mIsRtlLayout) { childRight = (getWidth() - paddingRight) - (mColCount - col - 1) * (colWidth + itemMargin); childLeft = childRight - child.getMeasuredWidth(); } else { childLeft = paddingLeft + col * (colWidth + itemMargin); childRight = childLeft + child.getMeasuredWidth(); } /* Log.v(TAG, "[layoutChildren] height: " + childHeight + " top: " + childTop + " bottom: " + childBottom + " left: " + childLeft + " column: " + col + " position: " + position + " id: " + lp.id); */ child.layout(childLeft, childTop, childRight, childBottom); if (lp.id == mFocusedChildIdToScrollIntoView) { child.requestFocus(); } for (int spanIndex = 0; spanIndex < span; spanIndex++) { final int index = mIsRtlLayout ? col - spanIndex : col + spanIndex; mItemBottoms[index] = childBottom; } // Whether or not LayoutRecords may have already existed for the view at this position // on screen, we'll update it after we lay out to ensure that the LayoutRecord // has the most updated information about the view at this position. We can be assured // that all views before those on screen (views with adapter position < mFirstPosition) // have the correct LayoutRecords because calculateLayoutStartOffsets() would have // set them appropriately. LayoutRecord rec = mLayoutRecords.get(position); if (rec == null) { rec = new LayoutRecord(); mLayoutRecords.put(position, rec); } rec.column = lp.column; rec.height = childHeight; rec.id = lp.id; rec.span = span; } // It appears that removeViewInLayout() does not invalidate. So if we make use of this // method during layout, we should invalidate explicitly. if (viewsRemovedInLayout || deferRecyclingForAnimation) { invalidate(); } }