Google最近发布了Android的新版本,其中包含一个如下所示的联系人应用程序:
我需要模仿这种列表,但我不知道如何做得好。
这包括3个主要组成部分:
stickey标题,只要顶级联系人的姓名以此字母开头,就会保留。
圆形照片或圆圈+字母(适用于没有照片的联系人)
PagerTitleStrip,项目间的间距均匀,并尝试在屏幕上显示所有内容(或允许在需要时滚动)。
有很多第三方库,但是处理stickey-headers,它们是listView本身项目的一部分。他们没有左边的标题,但是在项目的顶部。
这里,左侧以与右侧不同的方式移动。它可以粘住,如果不需要粘贴(例如,因为该部分有一个项目),它会滚动。
我注意到对于圆形照片,我可以使用名为“RoundedBitmapDrawableFactory”的新(?)类(创建“RoundedBitmapDrawable”)。这可能会让我很好地将照片变成圆形。但是,它不适用于字母(用于没有照片的联系人),但我想我可以在上面放置一个textView,并将背景设置为一种颜色。
另外,我注意到为了使用“RoundedBitmapDrawable”(使其成为真正的圆形),我必须为它提供一个方形大小的位图。否则,它将有一个奇怪的形状。
我尝试使用“setTextSpacing”来最小化项目之间的空间,但它似乎不起作用。我也找不到任何方式来设置/自定义PagerTitleStrip就像在联系人应用程序上一样。
我也尝试过使用“PagerTabStrip”,但也没有帮助。
您如何模仿Google实施此屏幕的方式?
更具体地说:
答案 0 :(得分:6)
1.我改变了第三方库的工作方式(我不记得我从哪里获得了库,但是this one非常相似),通过改变每一行的布局,所以标题将位于内容本身的左侧。它只是一个布局XML文件的问题,你已经完成了很多工作。也许我会为这两种解决方案发布一个很好的库。
2.这是我所做的观点。它不是官方的实施(没有找到),所以我自己做了些什么。它可以更有效率,但至少它很容易理解,而且非常灵活:
public class CircularView extends ViewSwitcher {
private ImageView mImageView;
private TextView mTextView;
private Bitmap mBitmap;
private CharSequence mText;
private int mBackgroundColor = 0;
private int mImageResId = 0;
public CircularView(final Context context) {
this(context, null);
}
public CircularView(final Context context, final AttributeSet attrs) {
super(context, attrs);
addView(mImageView = new ImageView(context), new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT, Gravity.CENTER));
addView(mTextView = new TextView(context), new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT, Gravity.CENTER));
mTextView.setGravity(Gravity.CENTER);
if (isInEditMode())
setTextAndBackgroundColor("", 0xFFff0000);
}
@Override
protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
final int measuredWidth = getMeasuredWidth();
final int measuredHeight = getMeasuredHeight();
if (measuredWidth != 0 && measuredHeight != 0)
drawContent(measuredWidth, measuredHeight);
}
@SuppressWarnings("deprecation")
private void drawContent(final int measuredWidth, final int measuredHeight) {
ShapeDrawable roundedBackgroundDrawable = null;
if (mBackgroundColor != 0) {
roundedBackgroundDrawable = new ShapeDrawable(new OvalShape());
roundedBackgroundDrawable.getPaint().setColor(mBackgroundColor);
roundedBackgroundDrawable.setIntrinsicHeight(measuredHeight);
roundedBackgroundDrawable.setIntrinsicWidth(measuredWidth);
roundedBackgroundDrawable.setBounds(new Rect(0, 0, measuredWidth, measuredHeight));
}
if (mImageResId != 0) {
mImageView.setBackgroundDrawable(roundedBackgroundDrawable);
mImageView.setImageResource(mImageResId);
mImageView.setScaleType(ScaleType.CENTER_INSIDE);
} else if (mText != null) {
mTextView.setText(mText);
mTextView.setBackgroundDrawable(roundedBackgroundDrawable);
// mTextView.setPadding(0, measuredHeight / 4, 0, measuredHeight / 4);
mTextView.setTextSize(measuredHeight / 5);
} else if (mBitmap != null) {
mImageView.setScaleType(ScaleType.FIT_CENTER);
mImageView.setBackgroundDrawable(roundedBackgroundDrawable);
mBitmap = ThumbnailUtils.extractThumbnail(mBitmap, measuredWidth, measuredHeight);
final RoundedBitmapDrawable roundedBitmapDrawable = RoundedBitmapDrawableFactory.create(getResources(),
mBitmap);
roundedBitmapDrawable.setCornerRadius((measuredHeight + measuredWidth) / 4);
mImageView.setImageDrawable(roundedBitmapDrawable);
}
resetValuesState(false);
}
public void setTextAndBackgroundColor(final CharSequence text, final int backgroundColor) {
resetValuesState(true);
while (getCurrentView() != mTextView)
showNext();
this.mBackgroundColor = backgroundColor;
mText = text;
final int height = getHeight(), width = getWidth();
if (height != 0 && width != 0)
drawContent(width, height);
}
public void setImageResource(final int imageResId, final int backgroundColor) {
resetValuesState(true);
while (getCurrentView() != mImageView)
showNext();
mImageResId = imageResId;
this.mBackgroundColor = backgroundColor;
final int height = getHeight(), width = getWidth();
if (height != 0 && width != 0)
drawContent(width, height);
}
public void setImageBitmap(final Bitmap bitmap) {
setImageBitmapAndBackgroundColor(bitmap, 0);
}
public void setImageBitmapAndBackgroundColor(final Bitmap bitmap, final int backgroundColor) {
resetValuesState(true);
while (getCurrentView() != mImageView)
showNext();
this.mBackgroundColor = backgroundColor;
mBitmap = bitmap;
final int height = getHeight(), width = getWidth();
if (height != 0 && width != 0)
drawContent(width, height);
}
private void resetValuesState(final boolean alsoResetViews) {
mBackgroundColor = mImageResId = 0;
mBitmap = null;
mText = null;
if (alsoResetViews) {
mTextView.setText(null);
mTextView.setBackgroundDrawable(null);
mImageView.setImageBitmap(null);
mImageView.setBackgroundDrawable(null);
}
}
public ImageView getImageView() {
return mImageView;
}
public TextView getTextView() {
return mTextView;
}
}
3.我找到了一个很棒的图书馆,名为PagerSlidingTabStrip。但是,没有找到一种正式的方式来塑造本土的风格。
另一种方法是查看Google的样本,该样本在Android-Studio中可用,并且被称为" SlidingTabLayout"。它显示了它是如何完成的。
编辑:#3的更好的库是here,称为#34; PagerSlidingTabStrip"太
答案 1 :(得分:1)
您可以执行以下操作:
要添加淡入/淡出过渡效果,请开发一个逻辑,检查currentFirstVisibleItem之前的项是否是前一个字母列表的最后一个,或者secondVisibleItem是否是新字母的第一个。基于这些信息,使粘性索引可见/不可见,行索引相反,在此最后添加alpha效果。
if (recyclerView != null) {
View firstVisibleView = recyclerView.getChildAt(0);
View secondVisibleView = recyclerView.getChildAt(1);
TextView firstRowIndex = (TextView) firstVisibleView.findViewById(R.id.sticky_row_index);
TextView secondRowIndex = (TextView) secondVisibleView.findViewById(R.id.sticky_row_index);
int visibleRange = recyclerView.getChildCount();
int actual = recyclerView.getChildPosition(firstVisibleView);
int next = actual + 1;
int previous = actual - 1;
int last = actual + visibleRange;
// RESET STICKY LETTER INDEX
stickyIndex.setText(String.valueOf(getIndexContext(firstRowIndex)).toUpperCase());
stickyIndex.setVisibility(TextView.VISIBLE);
if (dy > 0) {
// USER SCROLLING DOWN THE RecyclerView
if (next <= last) {
if (isHeader(firstRowIndex, secondRowIndex)) {
stickyIndex.setVisibility(TextView.INVISIBLE);
firstRowIndex.setVisibility(TextView.VISIBLE);
firstRowIndex.setAlpha(1 - (Math.abs(firstVisibleView.getY()) / firstRowIndex.getHeight()));
secondRowIndex.setVisibility(TextView.VISIBLE);
} else {
firstRowIndex.setVisibility(TextView.INVISIBLE);
stickyIndex.setVisibility(TextView.VISIBLE);
}
}
} else {
// USER IS SCROLLING UP THE RecyclerVIew
if (next <= last) {
// RESET FIRST ROW STATE
firstRowIndex.setVisibility(TextView.INVISIBLE);
if ((isHeader(firstRowIndex, secondRowIndex) || (getIndexContext(firstRowIndex) != getIndexContext(secondRowIndex))) && isHeader(firstRowIndex, secondRowIndex)) {
stickyIndex.setVisibility(TextView.INVISIBLE);
firstRowIndex.setVisibility(TextView.VISIBLE);
firstRowIndex.setAlpha(1 - (Math.abs(firstVisibleView.getY()) / firstRowIndex.getHeight()));
secondRowIndex.setVisibility(TextView.VISIBLE);
} else {
secondRowIndex.setVisibility(TextView.INVISIBLE);
}
}
}
if (stickyIndex.getVisibility() == TextView.VISIBLE) {
firstRowIndex.setVisibility(TextView.INVISIBLE);
}
}
我开发了一个执行上述逻辑的组件,可在此处找到:https://github.com/edsilfer/sticky-index
答案 2 :(得分:0)
应用程序的源代码总是一个好的开始
答案 3 :(得分:0)
我回答得这么晚,但希望我的回答对某人有帮助。我也有这样的任务。我一直在寻找答案和粘性标头的示例,但对于recyclerView。我在Saber Solooki的文章"Sticky Header For RecyclerView"中找到了最好,最简单的解决方案。
基于此示例,我为我的应用程序制作了联系模块,这非常简单。
答案 4 :(得分:0)
要实现类似于电话的联系人列表,This是我遇到的最佳解决方案!
这也可以与自定义列表一起使用,因为图像可能需要带有名称。上面的解决方案仅包含并非所有人都需要的String列表或数组!