我已经创建了一个基本的自定义视图来复制这种行为,它并不完全相同,但我认为它现在已经足够接近了,如果它需要完全相同,这可以通过修改 updateChildViews() 方法来快速实现。我在 20 分钟内写完这门课,所以它远非完美,对于生产就绪的解决方案,还需要做一些额外的工作。通常,此解决方案适用于所有类型的子视图,但要复制确切的行为,请使用 ImageView 作为子视图的背景,并在 ImageViews 上设置此属性:
android:scaleType="centerCrop"
我在当前状态下的解决方案中看到的问题:
- 仅适用于垂直方向
- 没有视图回收。
- 应该派生自 AdapterView 而不是 LinearLayout。
不管怎样,到目前为止是这样的:
这里是源代码:
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.LinearLayout;
public class Accordion extends LinearLayout {
private static final String LOG_TAG = Accordion.class.getSimpleName();
private double scrollProgress = 0.0;
private double topViewScaleFactor = 2.0;
private double collapsedViewHeight = 200.0;
private double expandedViewHeight = 700.0;
private double scrollProgressPerView = expandedViewHeight;
private final ScrollTouchListener touchListener = new ScrollTouchListener() {
@Override
protected void onScroll(float x, float y) {
scrollProgress += y;
if(scrollProgress < 0.0) {
scrollProgress = 0.0;
}
int viewCount = getChildCount();
double maxScrollProgress = (viewCount - 1) * scrollProgressPerView + 1;
if(scrollProgress > maxScrollProgress) {
scrollProgress = maxScrollProgress;
}
Log.i(LOG_TAG, String.format("Scroll Progress: %f", scrollProgress));
updateChildViews();
}
};
public Accordion(Context context) {
super(context);
this.setOnTouchListener(this.touchListener);
}
public Accordion(Context context, AttributeSet attrs) {
super(context, attrs);
this.setOnTouchListener(this.touchListener);
}
public Accordion(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
this.setOnTouchListener(this.touchListener);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
updateChildViews();
}
private void updateChildViews() {
int viewCount = getChildCount();
double progress = scrollProgress;
double overflow = 0;
for(int i = 0; i < viewCount; i++) {
View child = getChildAt(i);
if(child != null) {
if(progress >= scrollProgressPerView) {
progress -= scrollProgressPerView;
child.setVisibility(View.GONE);
setChildHeight(child, 0);
} else if (progress > 0) {
setChildHeight(child, expandedViewHeight - progress);
overflow = progress;
child.setVisibility(View.VISIBLE);
progress = 0;
} else {
if(overflow > 0) {
double height = collapsedViewHeight + overflow;
if(height > expandedViewHeight) {
height = expandedViewHeight;
}
setChildHeight(child, height);
overflow = 0;
} else {
setChildHeight(child, i > 0 ? collapsedViewHeight : expandedViewHeight);
}
child.setVisibility(View.VISIBLE);
}
}
}
}
private void setChildHeight(View child, double height) {
child.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, (int)height));
}
private static abstract class ScrollTouchListener implements OnTouchListener {
private static final String LOG_TAG = ScrollTouchListener.class.getSimpleName();
private boolean scrolling = false;
private float x = 0;
private float y = 0;
@Override
public boolean onTouch(View view, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
x = event.getX();
y = event.getY();
scrolling = true;
return true;
case MotionEvent.ACTION_UP:
scrolling = false;
return true;
case MotionEvent.ACTION_MOVE:
if (scrolling) {
float newX = event.getX();
float newY = event.getY();
float difX = x - newX;
float difY = y - newY;
onScroll(difX, difY);
x = newX;
y = newY;
}
return true;
default:
return false;
}
}
protected abstract void onScroll(float x, float y);
}
}
要使用它,只需将它放在这样的布局中:
<at.test.app.Accordion xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ImageView android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scaleType="centerCrop"
android:src="@drawable/alpen"/>
<ImageView android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scaleType="centerCrop"
android:src="@drawable/alpen"/>
<ImageView android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scaleType="centerCrop"
android:src="@drawable/alpen"/>
<ImageView android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scaleType="centerCrop"
android:src="@drawable/alpen"/>
</at.test.app.Accordion>
如果您有任何其他问题,请随时提出!