一、滚动过程悬浮
ScrollView悬浮是很常见的用法,之前用过StickScrollView,存在的问题是只是把View图像定位到了顶部,无法处理touch event。这里我们提供一种相对简单的View组件。
二、核心要点
layout方法top设置
bingToFront方法,该方法不会重新布局,但是会改变View层次
三、代码实现
public class FloatScrollView extends ScrollView {
private List<StickView> mStickView = null;
public FloatScrollView(Context context) {
this(context,null);
}
public FloatScrollView(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public FloatScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
int getRealChildCount(){
int childCount = getChildCount();
if(childCount==0) return 0;
ViewGroup wrapperView = (ViewGroup) getChildAt(0);
if(wrapperView==null) return 0;
return wrapperView.getChildCount();
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
if(!changed) return;
super.onLayout(changed, l, t, r, b);
if(mStickView==null){
mStickView = new ArrayList<>();
}else{
mStickView.clear();
}
int realChildCount = getRealChildCount();
for (int i=0;i<realChildCount;i++){
ViewGroup parent = (ViewGroup) getChildAt(0);
View child = parent.getChildAt(i);
Object tag = child.getTag();
if(!(tag instanceof CharSequence)) continue;
if("sticky".equals(tag)){
mStickView.add(new StickView(child));
}
}
}
@Override
protected void onScrollChanged(int sl, int st, int oldsl, int oldst) {
if(mStickView==null){
mStickView = new ArrayList<>();
}
for (int i=0;i<mStickView.size();i++){
StickView childView = mStickView.get(i);
int offset = childView.srcTop - st;
if(offset>0){
refreshTopOffset(childView.widget,childView.srcTop);
continue;
}
//让前面stickView的回归原始位置
for (int prev=i-1;prev>=0;prev--){
StickView preChildView = mStickView.get(i);
refreshTopOffset(preChildView.widget,preChildView.srcTop);
}
Log.d("FloatScrollView", "offset=" + offset + ", st="+st);
//计算下一个stcikview距离顶部的位置
int nextChildIndex = i+1;
if(nextChildIndex>mStickView.size()-1) {
refreshTopOffset(childView.widget, st);
}else {
StickView nextChildView = mStickView.get(nextChildIndex);
int nextChildOffset = nextChildView.srcTop - st;
if (nextChildOffset > childView.widget.getHeight()) {
refreshTopOffset(childView.widget, st);
} else {
float dx = childView.widget.getHeight() - nextChildOffset;
refreshTopOffset(childView.widget,st-dx);
}
}
}
super.onScrollChanged(sl, st, oldsl, oldst);
}
private void refreshTopOffset(View childView, float offset) {
int topOffset = (int) ( offset);
childView.layout(childView.getLeft(),topOffset,childView.getRight(),topOffset+childView.getHeight());
childView.bringToFront(); //解决被其他view遮挡问题
}
class StickView{
int srcTop;
View widget;
public StickView(View child) {
this.widget = child;
this.srcTop = child.getTop();
}
}
}