请使用1.0.1
implementation 'com.fxyan.widget:letterIndicatorView:1.0.1'
效果图如下
- livIndicatorBgColor指示器背景色;
- livIndicatorItemWidth指示器宽度;
- livIndicatorItemHeight指示器高度;
- livIndicatorTextSize指示器文本大小;
- livIndicatorSelectedTextColor指示器选中文本颜色;
- livIndicatorSelectedBgColor指示器选中文本背景色;
- livIndicatorSelectedBgRadius指示器选中文本背景半径(目前只有原型的背景);
- livIndicatorUnSelectTextColor指示器未选中文本颜色;
- livZoomUpIndicatorTextSize放大部分文本大小;
- livZoomUpIndicatorTextColor放大部分文本颜色;
- livZoomUpIndicatorBgColor放大部分背景颜色;
- livZoomUpIndicatorBgRadius放大部分圆的半径;
- livZoomUpIndicatorMargin放大部分和指示器之间的距离;
- livHeaderDrawable是否有列表头,列表头对应图标。
<com.fxyan.widget.LetterIndicatorView
android:id="@+id/indicatorView"
android:layout_width="wrap_content"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="@+id/recyclerView"
app:layout_constraintRight_toRightOf="@+id/recyclerView"
app:layout_constraintTop_toTopOf="@+id/recyclerView"
app:livHeaderDrawable="@mipmap/ic_search"
app:livIndicatorBgColor="@android:color/transparent"
app:livIndicatorItemHeight="15dp"
app:livIndicatorItemWidth="20dp"
app:livIndicatorSelectedBgColor="#43c561"
app:livIndicatorSelectedBgRadius="8dp"
app:livIndicatorSelectedTextColor="@android:color/white"
app:livIndicatorTextSize="10sp"
app:livIndicatorUnSelectTextColor="#646464"
app:livZoomUpIndicatorBgColor="#20000000"
app:livZoomUpIndicatorBgRadius="20dp"
app:livZoomUpIndicatorMargin="5dp"
app:livZoomUpIndicatorTextColor="@android:color/white"
app:livZoomUpIndicatorTextSize="20sp" />
可以给LetterIndicatorView设置OnIndicatorIndexChangeListener,index的取值范围大于等于-1。
public interface OnIndicatorIndexChangeListener {
void onIndicatorIndexChanged(int index);
}
默认配置了一个简单的ItemDecoration,如果刚好可以满足需求,你可以直接通过attachToRecyclerView()关联RecyclerView,对于ItemDecoration的配置可以通过DecorationConfig.Builder来进行构造
如果你使用attachToRecyclerView(),则需要配置一个DecorationConfig。
DecorationConfig config = new DecorationConfig.Builder()
.setLine(1, Color.parseColor("#ebebeb"))
.setSelectedTextColor(0x33, 0x33, 0x33)
.setUnSelectTextColor(0x64, 0x64, 0x64)
.setSelectedBgColor(0xff, 0xff, 0xff)
.setUnSelectBgColor(0xf8, 0xf9, 0xfa)
.setTextXOffset(Tools.dp2px(this, 12))
.setTextSize(Tools.dp2px(this, 14))
.setHeight((int) Tools.dp2px(this, 30))
.build();
indicatorView.attachToRecyclerView(recyclerView, config, array);
属性说明
- lineHeight分割线高度,通过setLine()设置;
- lineColor分割线颜色,通过setLine()设置;
- selectedTextColor,当前分组的文本颜色,这里将颜色拆分成R,G,B三原色,方便实现碰撞颜色的渐变效果,通过setSelectedTextColor()设置;
- unSelectTextColor,其他分组的文本颜色,通过setUnSelectTextColor()设置;
- selectedBgColor,当前分组的背景色,通过setSelectedBgColor()设置;
- unSelectBgColor,其他分组的文本颜色,通过setUnSelectBgColor设置;
- textSize,文本大小,通过setTextSize()设置;
- textXOffset,文本x轴偏移量,通过setTextXOffset()设置;
- height,分组高度,通过setHeight()设置。
如果自带的Decoration不支持需求,可以自己编写Decoration
碰撞效果在Decoration的onDrawOver()方法中
View firstVisibleView = parent.getChildAt(0);
int firstVisibleViewIndex = parent.getChildAdapterPosition(firstVisibleView);
View secondVisibleView = parent.getChildAt(1);
int secondVisibleViewIndex = parent.getChildAdapterPosition(secondVisibleView);
float top = 0;
if (array.indexOfKey(secondVisibleViewIndex) >= 0
&& firstVisibleView.getBottom() <= config.getHeight()) {
// 这里表示需要绘制碰撞效果,第二组的第一个元素刚好是RecyclerView的第二个子控件
top = firstVisibleView.getBottom() - config.getHeight();
// y轴偏移量
float yOffset = top + config.getHeight() / 2 - (fontMetrics.bottom + fontMetrics.top) / 2;
// ...绘制
}
onDraw()方法中主要是处理Item上的指示器渐变
public void onDraw(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
super.onDraw(c, parent, state);
for (int i = 0; i < parent.getChildCount(); i++) {
View child = parent.getChildAt(i);
int position = parent.getChildAdapterPosition(child);
if (array.indexOfKey(position) >= 0) {
String tmp = array.get(position);
float xOffset = config.getTextXOffset();
float yOffset = child.getTop() - config.getHeight() / 2 - (fontMetrics.bottom + fontMetrics.top) / 2;
View firstVisibleView = parent.getChildAt(0);
View secondVisibleView = parent.getChildAt(1);
int secondVisibleViewIndex = parent.getChildAdapterPosition(secondVisibleView);
int bgColor = Color.rgb(config.getUnSelectBgColorR(), config.getUnSelectBgColorG(), config.getUnSelectBgColorB());
int textColor = Color.rgb(config.getUnSelectTextColorR(), config.getUnSelectTextColorG(), config.getUnSelectTextColorB());
if (array.indexOfKey(secondVisibleViewIndex) >= 0 && secondVisibleViewIndex == position
&& firstVisibleView.getBottom() <= config.getHeight()) {
// 这里是计算碰撞的时候Item上的文本和背景的渐变颜色值
int currentTextR = config.getUnSelectTextColorR();
int currentTextG = config.getUnSelectTextColorG();
int currentTextB = config.getUnSelectTextColorB();
int currentBgR = config.getUnSelectBgColorR();
int currentBgG = config.getUnSelectBgColorG();
int currentBgB = config.getUnSelectBgColorB();
int endTextR = config.getSelectedTextColorR();
int endTextG = config.getSelectedTextColorG();
int endTextB = config.getSelectedTextColorB();
int endBgR = config.getSelectedBgColorR();
int endBgG = config.getSelectedBgColorG();
int endBgB = config.getSelectedBgColorB();
// 这里是计算渐变百分比
float percent = 1f * (config.getHeight() - firstVisibleView.getBottom()) / config.getHeight();
// text
currentTextR = (int) (currentTextR + (endTextR - currentTextR) * percent);
currentTextG = (int) (currentTextG + (endTextG - currentTextG) * percent);
currentTextB = (int) (currentTextB + (endTextB - currentTextB) * percent);
// bg
currentBgR = (int) (currentBgR + (endBgR - currentBgR) * percent);
currentBgG = (int) (currentBgG + (endBgG - currentBgG) * percent);
currentBgB = (int) (currentBgB + (endBgB - currentBgB) * percent);
bgColor = Color.rgb(currentBgR, currentBgG, currentBgB);
textColor = Color.rgb(currentTextR, currentTextG, currentTextB);
}
// ...
paint.setColor(bgColor);
c.drawRect(0, child.getTop() - config.getHeight() + config.getLineHeight(), child.getRight(), child.getTop() - config.getLineHeight(), paint);
paint.setColor(textColor);
c.drawText(tmp, xOffset, yOffset, paint);
}
}
}
onDrawOver()方法中主要是处理覆盖物上的指示器渐变。
public void onDrawOver(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
super.onDrawOver(c, parent, state);
View firstVisibleView = parent.getChildAt(0);
int firstVisibleViewIndex = parent.getChildAdapterPosition(firstVisibleView);
View secondVisibleView = parent.getChildAt(1);
int secondVisibleViewIndex = parent.getChildAdapterPosition(secondVisibleView);
// ...
float top = 0;
int currentTextR = config.getSelectedTextColorR();
int currentTextG = config.getSelectedTextColorG();
int currentTextB = config.getSelectedTextColorB();
int currentBgR = config.getSelectedBgColorR();
int currentBgG = config.getSelectedBgColorG();
int currentBgB = config.getSelectedBgColorB();
if (array.indexOfKey(secondVisibleViewIndex) >= 0
&& firstVisibleView.getBottom() <= config.getHeight()) {
// 第一个可见的控件是该组最后一个控件,这里是计算覆盖物的文本和背景的颜色值
top = firstVisibleView.getBottom() - config.getHeight();
// text
int endTextR = config.getUnSelectTextColorR();
int endTextG = config.getUnSelectTextColorG();
int endTextB = config.getUnSelectTextColorB();
// bg
int endBgR = config.getUnSelectBgColorR();
int endBgG = config.getUnSelectBgColorG();
int endBgB = config.getUnSelectBgColorB();
// 这里是渐变百分比
float percent = 1f * Math.abs(top) / config.getHeight();
currentTextR = (int) (currentTextR + (endTextR - currentTextR) * percent);
currentTextG = (int) (currentTextG + (endTextG - currentTextG) * percent);
currentTextB = (int) (currentTextB + (endTextB - currentTextB) * percent);
currentBgR = (int) (currentBgR + (endBgR - currentBgR) * percent);
currentBgG = (int) (currentBgG + (endBgG - currentBgG) * percent);
currentBgB = (int) (currentBgB + (endBgB - currentBgB) * percent);
}
paint.setColor(Color.rgb(currentBgR, currentBgG, currentBgB));
c.drawRect(0, top + config.getLineHeight(), parent.getWidth(), top + config.getHeight() - config.getLineHeight(), paint);
float xOffset = config.getTextXOffset();
float yOffset = top + config.getHeight() / 2 - (fontMetrics.bottom + fontMetrics.top) / 2;
int color = Color.rgb(currentTextR, currentTextG, currentTextB);
paint.setColor(color);
c.drawText(tmp, xOffset, yOffset, paint);
}