Merge "Add animation and positional stability to intent chooser UI" into mnc-dr-dev
This commit is contained in:
@@ -16,6 +16,8 @@
|
||||
|
||||
package com.android.internal.app;
|
||||
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.annotation.NonNull;
|
||||
import android.app.Activity;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
@@ -29,6 +31,7 @@ import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.database.DataSetObserver;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.graphics.drawable.Icon;
|
||||
import android.os.Bundle;
|
||||
@@ -46,13 +49,18 @@ import android.service.chooser.ChooserTargetService;
|
||||
import android.service.chooser.IChooserTargetResult;
|
||||
import android.service.chooser.IChooserTargetService;
|
||||
import android.text.TextUtils;
|
||||
import android.util.FloatProperty;
|
||||
import android.util.Log;
|
||||
import android.util.Slog;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.View.MeasureSpec;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.view.View.OnLongClickListener;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewGroup.LayoutParams;
|
||||
import android.view.animation.AnimationUtils;
|
||||
import android.view.animation.Interpolator;
|
||||
import android.widget.AbsListView;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.ListView;
|
||||
@@ -80,6 +88,7 @@ public class ChooserActivity extends ResolverActivity {
|
||||
private Intent mReferrerFillInIntent;
|
||||
|
||||
private ChooserListAdapter mChooserListAdapter;
|
||||
private ChooserRowAdapter mChooserRowAdapter;
|
||||
|
||||
private final List<ChooserTargetServiceConnection> mServiceConnections = new ArrayList<>();
|
||||
|
||||
@@ -253,7 +262,9 @@ public class ChooserActivity extends ResolverActivity {
|
||||
boolean alwaysUseOption) {
|
||||
final ListView listView = adapterView instanceof ListView ? (ListView) adapterView : null;
|
||||
mChooserListAdapter = (ChooserListAdapter) adapter;
|
||||
adapterView.setAdapter(new ChooserRowAdapter(mChooserListAdapter));
|
||||
mChooserRowAdapter = new ChooserRowAdapter(mChooserListAdapter);
|
||||
mChooserRowAdapter.registerDataSetObserver(new OffsetDataSetObserver(adapterView));
|
||||
adapterView.setAdapter(mChooserRowAdapter);
|
||||
if (listView != null) {
|
||||
listView.setItemsCanFocus(true);
|
||||
}
|
||||
@@ -913,19 +924,103 @@ public class ChooserActivity extends ResolverActivity {
|
||||
}
|
||||
}
|
||||
|
||||
static class RowScale {
|
||||
private static final int DURATION = 400;
|
||||
|
||||
float mScale;
|
||||
ChooserRowAdapter mAdapter;
|
||||
private final ObjectAnimator mAnimator;
|
||||
|
||||
public static final FloatProperty<RowScale> PROPERTY =
|
||||
new FloatProperty<RowScale>("scale") {
|
||||
@Override
|
||||
public void setValue(RowScale object, float value) {
|
||||
object.mScale = value;
|
||||
object.mAdapter.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float get(RowScale object) {
|
||||
return object.mScale;
|
||||
}
|
||||
};
|
||||
|
||||
public RowScale(@NonNull ChooserRowAdapter adapter, float from, float to) {
|
||||
mAdapter = adapter;
|
||||
mScale = from;
|
||||
if (from == to) {
|
||||
mAnimator = null;
|
||||
return;
|
||||
}
|
||||
|
||||
mAnimator = ObjectAnimator.ofFloat(this, PROPERTY, from, to).setDuration(DURATION);
|
||||
}
|
||||
|
||||
public RowScale setInterpolator(Interpolator interpolator) {
|
||||
if (mAnimator != null) {
|
||||
mAnimator.setInterpolator(interpolator);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public float get() {
|
||||
return mScale;
|
||||
}
|
||||
|
||||
public void startAnimation() {
|
||||
if (mAnimator != null) {
|
||||
mAnimator.start();
|
||||
}
|
||||
}
|
||||
|
||||
public void cancelAnimation() {
|
||||
if (mAnimator != null) {
|
||||
mAnimator.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ChooserRowAdapter extends BaseAdapter {
|
||||
private ChooserListAdapter mChooserListAdapter;
|
||||
private final LayoutInflater mLayoutInflater;
|
||||
private final int mColumnCount = 4;
|
||||
private RowScale[] mServiceTargetScale;
|
||||
private final Interpolator mInterpolator;
|
||||
|
||||
public ChooserRowAdapter(ChooserListAdapter wrappedAdapter) {
|
||||
mChooserListAdapter = wrappedAdapter;
|
||||
mLayoutInflater = LayoutInflater.from(ChooserActivity.this);
|
||||
|
||||
mInterpolator = AnimationUtils.loadInterpolator(ChooserActivity.this,
|
||||
android.R.interpolator.decelerate_quint);
|
||||
|
||||
wrappedAdapter.registerDataSetObserver(new DataSetObserver() {
|
||||
@Override
|
||||
public void onChanged() {
|
||||
super.onChanged();
|
||||
final int rcount = getServiceTargetRowCount();
|
||||
if (mServiceTargetScale == null
|
||||
|| mServiceTargetScale.length != rcount) {
|
||||
RowScale[] old = mServiceTargetScale;
|
||||
int oldRCount = old != null ? old.length : 0;
|
||||
mServiceTargetScale = new RowScale[rcount];
|
||||
if (old != null && rcount > 0) {
|
||||
System.arraycopy(old, 0, mServiceTargetScale, 0,
|
||||
Math.min(old.length, rcount));
|
||||
}
|
||||
|
||||
for (int i = rcount; i < oldRCount; i++) {
|
||||
old[i].cancelAnimation();
|
||||
}
|
||||
|
||||
for (int i = oldRCount; i < rcount; i++) {
|
||||
final RowScale rs = new RowScale(ChooserRowAdapter.this, 0.f, 1.f)
|
||||
.setInterpolator(mInterpolator);
|
||||
mServiceTargetScale[i] = rs;
|
||||
rs.startAnimation();
|
||||
}
|
||||
}
|
||||
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@@ -933,19 +1028,43 @@ public class ChooserActivity extends ResolverActivity {
|
||||
public void onInvalidated() {
|
||||
super.onInvalidated();
|
||||
notifyDataSetInvalidated();
|
||||
if (mServiceTargetScale != null) {
|
||||
for (RowScale rs : mServiceTargetScale) {
|
||||
rs.cancelAnimation();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private float getRowScale(int rowPosition) {
|
||||
final int start = getCallerTargetRowCount();
|
||||
final int end = start + getServiceTargetRowCount();
|
||||
if (rowPosition >= start && rowPosition < end) {
|
||||
return mServiceTargetScale[rowPosition - start].get();
|
||||
}
|
||||
return 1.f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return (int) (
|
||||
Math.ceil((float) mChooserListAdapter.getCallerTargetCount() / mColumnCount)
|
||||
+ Math.ceil((float) mChooserListAdapter.getServiceTargetCount() / mColumnCount)
|
||||
getCallerTargetRowCount()
|
||||
+ getServiceTargetRowCount()
|
||||
+ Math.ceil((float) mChooserListAdapter.getStandardTargetCount() / mColumnCount)
|
||||
);
|
||||
}
|
||||
|
||||
public int getCallerTargetRowCount() {
|
||||
return (int) Math.ceil(
|
||||
(float) mChooserListAdapter.getCallerTargetCount() / mColumnCount);
|
||||
}
|
||||
|
||||
public int getServiceTargetRowCount() {
|
||||
return (int) Math.ceil(
|
||||
(float) mChooserListAdapter.getServiceTargetCount() / mColumnCount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getItem(int position) {
|
||||
// We have nothing useful to return here.
|
||||
@@ -959,33 +1078,67 @@ public class ChooserActivity extends ResolverActivity {
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
final View[] holder;
|
||||
final RowViewHolder holder;
|
||||
if (convertView == null) {
|
||||
holder = createViewHolder(parent);
|
||||
} else {
|
||||
holder = (View[]) convertView.getTag();
|
||||
holder = (RowViewHolder) convertView.getTag();
|
||||
}
|
||||
bindViewHolder(position, holder);
|
||||
|
||||
// We keep the actual list item view as the last item in the holder array
|
||||
return holder[mColumnCount];
|
||||
return holder.row;
|
||||
}
|
||||
|
||||
View[] createViewHolder(ViewGroup parent) {
|
||||
final View[] holder = new View[mColumnCount + 1];
|
||||
|
||||
RowViewHolder createViewHolder(ViewGroup parent) {
|
||||
final ViewGroup row = (ViewGroup) mLayoutInflater.inflate(R.layout.chooser_row,
|
||||
parent, false);
|
||||
final RowViewHolder holder = new RowViewHolder(row, mColumnCount);
|
||||
final int spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
|
||||
|
||||
for (int i = 0; i < mColumnCount; i++) {
|
||||
holder[i] = mChooserListAdapter.createView(row);
|
||||
row.addView(holder[i]);
|
||||
final View v = mChooserListAdapter.createView(row);
|
||||
v.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
startSelected(holder.itemIndex, false, true);
|
||||
}
|
||||
});
|
||||
v.setOnLongClickListener(new OnLongClickListener() {
|
||||
@Override
|
||||
public boolean onLongClick(View v) {
|
||||
showAppDetails(
|
||||
mChooserListAdapter.resolveInfoForPosition(holder.itemIndex, true));
|
||||
return true;
|
||||
}
|
||||
});
|
||||
row.addView(v);
|
||||
holder.cells[i] = v;
|
||||
|
||||
// Force height to be a given so we don't have visual disruption during scaling.
|
||||
LayoutParams lp = v.getLayoutParams();
|
||||
v.measure(spec, spec);
|
||||
if (lp == null) {
|
||||
lp = new LayoutParams(LayoutParams.MATCH_PARENT, v.getMeasuredHeight());
|
||||
row.setLayoutParams(lp);
|
||||
} else {
|
||||
lp.height = v.getMeasuredHeight();
|
||||
}
|
||||
}
|
||||
|
||||
// Pre-measure so we can scale later.
|
||||
holder.measure();
|
||||
LayoutParams lp = row.getLayoutParams();
|
||||
if (lp == null) {
|
||||
lp = new LayoutParams(LayoutParams.MATCH_PARENT, holder.measuredRowHeight);
|
||||
row.setLayoutParams(lp);
|
||||
} else {
|
||||
lp.height = holder.measuredRowHeight;
|
||||
}
|
||||
row.setTag(holder);
|
||||
holder[mColumnCount] = row;
|
||||
return holder;
|
||||
}
|
||||
|
||||
void bindViewHolder(int rowPosition, View[] holder) {
|
||||
void bindViewHolder(int rowPosition, RowViewHolder holder) {
|
||||
final int start = getFirstRowPosition(rowPosition);
|
||||
final int startType = mChooserListAdapter.getPositionTargetType(start);
|
||||
|
||||
@@ -994,34 +1147,26 @@ public class ChooserActivity extends ResolverActivity {
|
||||
end--;
|
||||
}
|
||||
|
||||
final ViewGroup row = (ViewGroup) holder[mColumnCount];
|
||||
|
||||
if (startType == ChooserListAdapter.TARGET_SERVICE) {
|
||||
row.setBackgroundColor(getColor(R.color.chooser_service_row_background_color));
|
||||
holder.row.setBackgroundColor(
|
||||
getColor(R.color.chooser_service_row_background_color));
|
||||
} else {
|
||||
row.setBackground(null);
|
||||
holder.row.setBackgroundColor(Color.TRANSPARENT);
|
||||
}
|
||||
|
||||
final int oldHeight = holder.row.getLayoutParams().height;
|
||||
holder.row.getLayoutParams().height = Math.max(1,
|
||||
(int) (holder.measuredRowHeight * getRowScale(rowPosition)));
|
||||
if (holder.row.getLayoutParams().height != oldHeight) {
|
||||
holder.row.requestLayout();
|
||||
}
|
||||
|
||||
for (int i = 0; i < mColumnCount; i++) {
|
||||
final View v = holder[i];
|
||||
final View v = holder.cells[i];
|
||||
if (start + i <= end) {
|
||||
v.setVisibility(View.VISIBLE);
|
||||
final int itemIndex = start + i;
|
||||
mChooserListAdapter.bindView(itemIndex, v);
|
||||
v.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
startSelected(itemIndex, false, true);
|
||||
}
|
||||
});
|
||||
v.setOnLongClickListener(new OnLongClickListener() {
|
||||
@Override
|
||||
public boolean onLongClick(View v) {
|
||||
showAppDetails(
|
||||
mChooserListAdapter.resolveInfoForPosition(itemIndex, true));
|
||||
return true;
|
||||
}
|
||||
});
|
||||
holder.itemIndex = start + i;
|
||||
mChooserListAdapter.bindView(holder.itemIndex, v);
|
||||
} else {
|
||||
v.setVisibility(View.GONE);
|
||||
}
|
||||
@@ -1048,6 +1193,24 @@ public class ChooserActivity extends ResolverActivity {
|
||||
}
|
||||
}
|
||||
|
||||
static class RowViewHolder {
|
||||
final View[] cells;
|
||||
final ViewGroup row;
|
||||
int measuredRowHeight;
|
||||
int itemIndex;
|
||||
|
||||
public RowViewHolder(ViewGroup row, int cellCount) {
|
||||
this.row = row;
|
||||
this.cells = new View[cellCount];
|
||||
}
|
||||
|
||||
public void measure() {
|
||||
final int spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
|
||||
row.measure(spec, spec);
|
||||
measuredRowHeight = row.getMeasuredHeight();
|
||||
}
|
||||
}
|
||||
|
||||
static class ChooserTargetServiceConnection implements ServiceConnection {
|
||||
private final DisplayResolveInfo mOriginalTarget;
|
||||
private ComponentName mConnectedComponent;
|
||||
@@ -1199,4 +1362,44 @@ public class ChooserActivity extends ResolverActivity {
|
||||
mSelectedTarget = null;
|
||||
}
|
||||
}
|
||||
|
||||
class OffsetDataSetObserver extends DataSetObserver {
|
||||
private final AbsListView mListView;
|
||||
private int mCachedViewType = -1;
|
||||
private View mCachedView;
|
||||
|
||||
public OffsetDataSetObserver(AbsListView listView) {
|
||||
mListView = listView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChanged() {
|
||||
if (mResolverDrawerLayout == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final int chooserTargetRows = mChooserRowAdapter.getServiceTargetRowCount();
|
||||
int offset = 0;
|
||||
for (int i = 0; i < chooserTargetRows; i++) {
|
||||
final int pos = mChooserRowAdapter.getCallerTargetRowCount() + i;
|
||||
final int vt = mChooserRowAdapter.getItemViewType(pos);
|
||||
if (vt != mCachedViewType) {
|
||||
mCachedView = null;
|
||||
}
|
||||
final View v = mChooserRowAdapter.getView(pos, mCachedView, mListView);
|
||||
int height = ((RowViewHolder) (v.getTag())).measuredRowHeight;
|
||||
|
||||
offset += (int) (height * mChooserRowAdapter.getRowScale(pos) * chooserTargetRows);
|
||||
|
||||
if (vt >= 0) {
|
||||
mCachedViewType = vt;
|
||||
mCachedView = v;
|
||||
} else {
|
||||
mCachedViewType = -1;
|
||||
}
|
||||
}
|
||||
|
||||
mResolverDrawerLayout.setCollapsibleHeightReserved(offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,6 +103,8 @@ public class ResolverActivity extends Activity {
|
||||
private ResolverComparator mResolverComparator;
|
||||
private PickTargetOptionRequest mPickOptionRequest;
|
||||
|
||||
protected ResolverDrawerLayout mResolverDrawerLayout;
|
||||
|
||||
private boolean mRegistered;
|
||||
private final PackageMonitor mPackageMonitor = new PackageMonitor() {
|
||||
@Override public void onSomePackagesChanged() {
|
||||
@@ -253,6 +255,7 @@ public class ResolverActivity extends Activity {
|
||||
if (isVoiceInteraction()) {
|
||||
rdl.setCollapsed(false);
|
||||
}
|
||||
mResolverDrawerLayout = rdl;
|
||||
}
|
||||
|
||||
if (title == null) {
|
||||
@@ -1570,7 +1573,10 @@ public class ResolverActivity extends Activity {
|
||||
|
||||
private void onBindView(View view, TargetInfo info) {
|
||||
final ViewHolder holder = (ViewHolder) view.getTag();
|
||||
holder.text.setText(info.getDisplayLabel());
|
||||
final CharSequence label = info.getDisplayLabel();
|
||||
if (!TextUtils.equals(holder.text.getText(), label)) {
|
||||
holder.text.setText(info.getDisplayLabel());
|
||||
}
|
||||
if (showsExtendedInfo(info)) {
|
||||
holder.text2.setVisibility(View.VISIBLE);
|
||||
holder.text2.setText(info.getExtendedInfo());
|
||||
|
||||
@@ -69,6 +69,12 @@ public class ResolverDrawerLayout extends ViewGroup {
|
||||
private int mCollapsibleHeight;
|
||||
private int mUncollapsibleHeight;
|
||||
|
||||
/**
|
||||
* The height in pixels of reserved space added to the top of the collapsed UI;
|
||||
* e.g. chooser targets
|
||||
*/
|
||||
private int mCollapsibleHeightReserved;
|
||||
|
||||
private int mTopOffset;
|
||||
|
||||
private boolean mIsDragging;
|
||||
@@ -153,12 +159,62 @@ public class ResolverDrawerLayout extends ViewGroup {
|
||||
}
|
||||
}
|
||||
|
||||
public void setCollapsibleHeightReserved(int heightPixels) {
|
||||
final int oldReserved = mCollapsibleHeightReserved;
|
||||
mCollapsibleHeightReserved = heightPixels;
|
||||
|
||||
final int dReserved = mCollapsibleHeightReserved - oldReserved;
|
||||
if (dReserved != 0 && mIsDragging) {
|
||||
mLastTouchY -= dReserved;
|
||||
}
|
||||
|
||||
final int oldCollapsibleHeight = mCollapsibleHeight;
|
||||
mCollapsibleHeight = Math.max(mCollapsibleHeight, getMaxCollapsedHeight());
|
||||
|
||||
if (updateCollapseOffset(oldCollapsibleHeight, !isDragging())) {
|
||||
return;
|
||||
}
|
||||
|
||||
invalidate();
|
||||
}
|
||||
|
||||
private boolean isMoving() {
|
||||
return mIsDragging || !mScroller.isFinished();
|
||||
}
|
||||
|
||||
private boolean isDragging() {
|
||||
return mIsDragging || getNestedScrollAxes() == SCROLL_AXIS_VERTICAL;
|
||||
}
|
||||
|
||||
private boolean updateCollapseOffset(int oldCollapsibleHeight, boolean remainClosed) {
|
||||
if (oldCollapsibleHeight == mCollapsibleHeight) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isLaidOut()) {
|
||||
final boolean isCollapsedOld = mCollapseOffset != 0;
|
||||
if (remainClosed && (oldCollapsibleHeight < mCollapsibleHeight
|
||||
&& mCollapseOffset == oldCollapsibleHeight)) {
|
||||
// Stay closed even at the new height.
|
||||
mCollapseOffset = mCollapsibleHeight;
|
||||
} else {
|
||||
mCollapseOffset = Math.min(mCollapseOffset, mCollapsibleHeight);
|
||||
}
|
||||
final boolean isCollapsedNew = mCollapseOffset != 0;
|
||||
if (isCollapsedOld != isCollapsedNew) {
|
||||
notifyViewAccessibilityStateChangedIfNeeded(
|
||||
AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
|
||||
}
|
||||
} else {
|
||||
// Start out collapsed at first unless we restored state for otherwise
|
||||
mCollapseOffset = mOpenOnLayout ? 0 : mCollapsibleHeight;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private int getMaxCollapsedHeight() {
|
||||
return isSmallCollapsed() ? mMaxCollapsedHeightSmall : mMaxCollapsedHeight;
|
||||
return (isSmallCollapsed() ? mMaxCollapsedHeightSmall : mMaxCollapsedHeight)
|
||||
+ mCollapsibleHeightReserved;
|
||||
}
|
||||
|
||||
public void setOnDismissedListener(OnDismissedListener listener) {
|
||||
@@ -676,7 +732,7 @@ public class ResolverDrawerLayout extends ViewGroup {
|
||||
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
|
||||
if (lp.alwaysShow && child.getVisibility() != GONE) {
|
||||
measureChildWithMargins(child, widthSpec, widthPadding, heightSpec, heightUsed);
|
||||
heightUsed += lp.topMargin + child.getMeasuredHeight() + lp.bottomMargin;
|
||||
heightUsed += getHeightUsed(child);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -688,7 +744,7 @@ public class ResolverDrawerLayout extends ViewGroup {
|
||||
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
|
||||
if (!lp.alwaysShow && child.getVisibility() != GONE) {
|
||||
measureChildWithMargins(child, widthSpec, widthPadding, heightSpec, heightUsed);
|
||||
heightUsed += lp.topMargin + child.getMeasuredHeight() + lp.bottomMargin;
|
||||
heightUsed += getHeightUsed(child);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -697,30 +753,43 @@ public class ResolverDrawerLayout extends ViewGroup {
|
||||
heightUsed - alwaysShowHeight - getMaxCollapsedHeight());
|
||||
mUncollapsibleHeight = heightUsed - mCollapsibleHeight;
|
||||
|
||||
if (isLaidOut()) {
|
||||
final boolean isCollapsedOld = mCollapseOffset != 0;
|
||||
if (oldCollapsibleHeight < mCollapsibleHeight
|
||||
&& mCollapseOffset == oldCollapsibleHeight) {
|
||||
// Stay closed even at the new height.
|
||||
mCollapseOffset = mCollapsibleHeight;
|
||||
} else {
|
||||
mCollapseOffset = Math.min(mCollapseOffset, mCollapsibleHeight);
|
||||
}
|
||||
final boolean isCollapsedNew = mCollapseOffset != 0;
|
||||
if (isCollapsedOld != isCollapsedNew) {
|
||||
notifyViewAccessibilityStateChangedIfNeeded(
|
||||
AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
|
||||
}
|
||||
} else {
|
||||
// Start out collapsed at first unless we restored state for otherwise
|
||||
mCollapseOffset = mOpenOnLayout ? 0 : mCollapsibleHeight;
|
||||
}
|
||||
updateCollapseOffset(oldCollapsibleHeight, !isDragging());
|
||||
|
||||
mTopOffset = Math.max(0, heightSize - heightUsed) + (int) mCollapseOffset;
|
||||
|
||||
setMeasuredDimension(sourceWidth, heightSize);
|
||||
}
|
||||
|
||||
private int getHeightUsed(View child) {
|
||||
// This method exists because we're taking a fast path at measuring ListViews that
|
||||
// lets us get away with not doing the more expensive wrap_content measurement which
|
||||
// imposes double child view measurement costs. If we're looking at a ListView, we can
|
||||
// check against the lowest child view plus padding and margin instead of the actual
|
||||
// measured height of the ListView. This lets the ListView hang off the edge when
|
||||
// all of the content would fit on-screen.
|
||||
|
||||
int heightUsed = child.getMeasuredHeight();
|
||||
if (child instanceof AbsListView) {
|
||||
final AbsListView lv = (AbsListView) child;
|
||||
final int lvPaddingBottom = lv.getPaddingBottom();
|
||||
|
||||
int lowest = 0;
|
||||
for (int i = 0, N = lv.getChildCount(); i < N; i++) {
|
||||
final int bottom = lv.getChildAt(i).getBottom() + lvPaddingBottom;
|
||||
if (bottom > lowest) {
|
||||
lowest = bottom;
|
||||
}
|
||||
}
|
||||
|
||||
if (lowest < heightUsed) {
|
||||
heightUsed = lowest;
|
||||
}
|
||||
}
|
||||
|
||||
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
|
||||
return lp.topMargin + heightUsed + lp.bottomMargin;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int l, int t, int r, int b) {
|
||||
final int width = getWidth();
|
||||
|
||||
@@ -85,7 +85,7 @@
|
||||
|
||||
<ListView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:id="@+id/resolver_list"
|
||||
android:clipToPadding="false"
|
||||
android:scrollbarStyle="outsideOverlay"
|
||||
|
||||
@@ -70,6 +70,7 @@
|
||||
android:minLines="2"
|
||||
android:maxLines="2"
|
||||
android:gravity="top|center_horizontal"
|
||||
android:ellipsize="marquee" />
|
||||
android:ellipsize="marquee"
|
||||
android:visibility="gone" />
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user