在前面的文章已经介绍了横向ListView的基础实现及头尾视图的添加等的实现,这篇文章将介绍为横向ListView添加滚动条;这一功能的添加和前面章节有些不同,前面章节添加功能都是在原来的控件上追加的,而滚动条的实现是以一个独立的控件存在的,以组合的形式添加到横向ListView中。
滚动条的实现思路:
1.计算横向ListView可见区域的宽度
2.计算整个横向ListView中所有数据都显示时的视图宽度(即理论上整个列表应该有的宽度)
3.计算出左边不可见的部分理论上应该有的宽度
4.根据比例计算出当前滚动条的显示宽度及显示位置(即width和left的值)
5.将滚动条控件组合到横向ListView中,同时设置显示开关
先上完整源码:
1.滚动条控件源码:
package com.hss.os.horizontallistview;
import android.content.Context;
import android.graphics.Color;
import android.os.Build;
import android.os.Handler;
import android.os.Message;
import android.support.annotation.RequiresApi;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
/**
* Created by Administrator on 2017/8/9.
*/
public class ScrollBar extends View {
private AlphaAnimation animation;
private int defaultVal=5;//滚动条的默认宽高值
private ShowType type=ShowType.horizontal;
private enum ShowType{
horizontal,
vertical
}
public ScrollBar(Context context) {
super(context);
init(context);
}
public ScrollBar(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public ScrollBar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public ScrollBar(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(context);
}
private void init(Context context){
setBackgroundColor(Color.parseColor("#3c3f41"));//设置默认背景颜色
//创建AlphaAnimation(透明度动画)
animation=new AlphaAnimation(1.0f, 0.1f);
//设置动画时间
animation.setDuration(1500);
//设置动画重复次数
animation.setRepeatCount(0);
animation.setAnimationListener(animationListener);
}
Handler handler=new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
startAnimation(animation);
return false;
}
});
private Animation.AnimationListener animationListener=new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
setVisibility(INVISIBLE);//使用INVISIBLE而不是使用GONE,是因为GONE会触发requestLayout()执行,导致界面刷新
}
@Override
public void onAnimationRepeat(Animation animation) {
}
};
/**
* 将滚动条从父布局中移除
* 必须调用这个方法执行移除操作,否则动画执行会有问题
* @param parent
*/
public void remove(ViewGroup parent){
handler.removeMessages(0);
//必须在从父布局中移除之前调用clearAnimation(),否则之后的动画执行会有问题
clearAnimation();
parent.removeViewInLayout(this);
}
/**
* 控件没有使用头尾视图设定时使用
* @param parent 父容器视图
* @param firstItemIndex 在可见区域内第一个item的下标(不包含头视图)
* @param lastItemIndex 在可见区域内最后一个item的下标(不包含尾视图)
* @param itemCount 所有的item总个数(不包含头尾视图)
*/
public void showVertical(ViewGroup parent,int firstItemIndex,int lastItemIndex,int itemCount){
showVertical(parent,firstItemIndex,lastItemIndex,itemCount,0,0);
}
/**
* 控件有使用头尾视图时使用
* @param parent 父容器视图
* @param firstItemIndex 在可见区域内第一个item的下标(不包含头视图)
* @param lastItemIndex 在可见区域内最后一个item的下标(不包含尾视图)
* @param itemCount 所有的item总个数(不包含头尾视图)
* @param headVal 显示的头视图高度
* @param footVal 显示的尾视图高度
*/
public void showVertical(ViewGroup parent,int firstItemIndex,int lastItemIndex,int itemCount,int headVal,int footVal){
type=ShowType.vertical;
show(parent,firstItemIndex,lastItemIndex,itemCount,headVal,footVal);
}
/**
* 控件没有使用头尾视图设定时使用
* @param parent 父容器视图
* @param firstItemIndex 在可见区域内第一个item的下标(不包含头视图)
* @param lastItemIndex 在可见区域内最后一个item的下标(不包含尾视图)
* @param itemCount 所有的item总个数(不包含头尾视图)
*/
public void showHorizontal(ViewGroup parent,int firstItemIndex,int lastItemIndex,int itemCount){
showHorizontal(parent,firstItemIndex,lastItemIndex,itemCount,0,0);
}
/**
* 控件有使用头尾视图时使用
* @param parent 父容器视图
* @param firstItemIndex 在可见区域内第一个item的下标(不包含头视图)
* @param lastItemIndex 在可见区域内最后一个item的下标(不包含尾视图)
* @param itemCount 所有的item总个数(不包含头尾视图)
* @param headVal 显示的头视图宽度
* @param footVal 显示的尾视图宽度
*/
public void showHorizontal(ViewGroup parent,int firstItemIndex,int lastItemIndex,int itemCount,int headVal,int footVal){
type=ShowType.horizontal;
show(parent,firstItemIndex,lastItemIndex,itemCount,headVal,footVal);
}
private int estimateVal=0;//预估的整个视图所有子项都显示出来时的高/宽(包含头尾视图)
private int averageVal=0;//预估的每一个子视图的高/宽(item的平均高度)
private int showCount=0;//当前显示的子项个数(不包含头、尾视图)
/**
*
* @param parent 父容器视图
* @param firstItemIndex 在可见区域内第一个item的下标(不包含头视图)
* @param lastItemIndex 在可见区域内最后一个item的下标(不包含尾视图)
* @param itemCount 所有的item总个数(不包含头尾视图)
* @param headVal 显示的头视图高度
* @param footVal 显示的尾视图高度
*/
private void show(ViewGroup parent,int firstItemIndex,int lastItemIndex,int itemCount,int headVal,int footVal){
setVisibility(INVISIBLE);//使用INVISIBLE而不是使用GONE,是因为GONE会触发requestLayout()执行,导致界面刷新
if(parent.getChildCount()==0) return;//没有子视图则不显示滚动条
//以下五行对数据的调整,是为了确保数据在逻辑上的正确性,确保之下的计算不会出现逻辑以外的情况
firstItemIndex=firstItemIndex<0?0:firstItemIndex;
lastItemIndex=lastItemIndex<0?0:lastItemIndex;
lastItemIndex=lastItemIndex<firstItemIndex?firstItemIndex:lastItemIndex;
itemCount=itemCount<=0?1:itemCount;
itemCount=itemCount<=lastItemIndex? lastItemIndex+1:itemCount;
if(lastItemIndex==0&&headVal==0&&footVal==0) return;//如果没有显示内容,则不显示滚动条
showCount=lastItemIndex-firstItemIndex+1;
ViewGroup.LayoutParams params=getLayoutParams();
int left=0,top=0,right=0,bottom=0;
switch (