今天写了ScrollView的下拉,弹性显示底部内容继续加载的例子,之所以不用ListView是因为ListView基本只能一列,不好实现瀑布流效果,而ScrollView基本没什么限制,所以就简单实现了一下ScrollView的相同效果,看了网上的很多相似的做法,写得确实很不错,不过看起来还是比较费劲的,本人新手,尽量就按照自己的理解,简易的实现了一下,东西内容不多,就显示和隐藏的一般逻辑,没有太多界面上复杂的东西首先,个人实现的原理,原理也很简单,就是重写ScrollView的OnTouchEvent方法来实现对ScrollView,触屏事件的监听把"继续加载"的View放在下方,设置BottomPadding为负的View高度,所以一开始就不显示了当滚动到ScrollView的子View显示完后,再不断的设置"继续加载View"的BottomPadding,于是"继续加载View"就能不断显示了,将该VIew不断隐藏也是同样的原理。主要的实现类
界面xml文件
实现过程还是比较简单的, 代码都在这了 , 没什么其他内容了 , 源程序在 这里
public class LaScrollView extends ScrollView implements ShowHide {
LinearLayout llController, llRefresh;
LinearLayout llContent;
// llContent是否滚到底
boolean isBottom;
int svHeight;
int llControllerHeight;
int llRefreshHeight;
TextView tvView;
LaScrollView sv = this;
// 是否可以进行加载
boolean continueLoad = false;
public void init() {
measureView(llController);
measureView(llRefresh);
llControllerHeight = llController.getMeasuredHeight();
llRefreshHeight = llRefresh.getMeasuredHeight();
showHide(0, false);
}
public LaScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
}
// 估计/计算View的高度
private void measureView(View child) {
ViewGroup.LayoutParams p = child.getLayoutParams();
if (p == null) {
p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
}
int childWidthSpec = ViewGroup.getChildMeasureSpec(0, 0, p.width);
int lpHeight = p.height;
int childHeightSpec;
if (lpHeight > 0) {
childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight,
MeasureSpec.EXACTLY);
} else {
childHeightSpec = MeasureSpec.makeMeasureSpec(0,
MeasureSpec.UNSPECIFIED);
}
child.measure(childWidthSpec, childHeightSpec);
}
float y;
public boolean onTouchEvent(MotionEvent event) {
float curY = event.getY();
float moveY; // 等于 curY - y; 负数表示手指向上 ,正数表示手指向下
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
y = curY;
break;
case MotionEvent.ACTION_MOVE:
moveY = curY - y;
Log.v("moveY ", "" + moveY);
if (moveY < 0) {// 向上滑动,有可能要显示隐藏的VIew
if (sv.getHeight() + sv.getScrollY() == llController
.getHeight()) {
isBottom = true;
}
}
if (isBottom) { // llContent滚到底端
if (moveY > 0) { // 慢慢隐藏
showHide((int) (-moveY - 1), true);
} else {// 有可能会拉出隐藏View
showHide((int) (-moveY), true);
}
}
y = curY;
break;
case MotionEvent.ACTION_UP:
y = curY;
if (continueLoad) {// 可以加载状态下松手
TextView child = new TextView(getContext());
showHide(0, false);
child.setText("我是新来的");
llContent.addView(child);
continueLoad = false;
} else {
showHide(0, false);
}
tvView.setText("向上拖动进行加载");
break;
}
return super.onTouchEvent(event);
};
@Override
public void showHide(int move, boolean isShow) {
// TODO Auto-generated method stub
if (isShow) {
llRefresh.setVisibility(View.VISIBLE);
int olePadding = llRefresh.getPaddingBottom();
int newPadding = olePadding + move;
Log.v("new Padding ", " move " + move + " \n" + newPadding);
if (move > 0) {// 不断显示
if (newPadding > 0) {
llRefresh.setPadding(0, 0, 0, 0);
} else {
if (((float) (llRefreshHeight + newPadding))
/ llRefreshHeight > 0.9) {// 设置什么时候可以刷新条件自己定
tvView.setText("放手继续加载");
continueLoad = true;
}
llRefresh.setPadding(0, 0, 0, newPadding);
}
} else {// 不停隐藏
int neHeight = -llRefreshHeight;
if (newPadding < neHeight) {
llRefresh.setPadding(0, 0, 0, neHeight);
isBottom = false;
} else {
if (((float) (llRefreshHeight + newPadding))
/ llRefreshHeight < 0.9) {// 设置什么时候可以刷新条件自己定
tvView.setText("向上拖动进行加载");
continueLoad = false;
}
llRefresh.setPadding(0, 0, 0, newPadding);
}
}
} else {
llRefresh.setPadding(0, 0, 0, -llRefreshHeight);
}
}
public void setLlController(LinearLayout llController) {
this.llController = llController;
}
public void setLlContent(LinearLayout llContent) {
this.llContent = llContent;
}
public void setLlRefresh(LinearLayout llRefresh) {
this.llRefresh = llRefresh;
}
public void setTvView(TextView tvView) {
this.tvView = tvView;
}
}
interface ShowHide {
public void showHide(int move, boolean isShow);
}
主要的加载Activity,内容不多
public class MainActivity extends Activity {
LayoutInflater inflater;
LaScrollView sv;
LinearLayout llController,llRefresh;
LinearLayout llContent;
TextView tvView;
//是否滚到底
boolean isBottom;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setup();
}
private void setup(){
inflater = LayoutInflater.from(this);
sv = (LaScrollView) findViewById(R.id.sv);
llController = (LinearLayout) findViewById(R.id.llComtroller);
llContent = (LinearLayout) findViewById(R.id.llContent);
llRefresh = (LinearLayout) findViewById(R.id.refreshLayout);
tvView = (TextView) findViewById(R.id.head_tipsTextView);
//为了看起来简洁,更好阅读, 界面十分简易
for (int i = 0; i < 40; i++) {
TextView tv = new TextView(this);
tv.setText("哈哈哈哈啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊");
llContent.addView(tv);
}
//把sv和相关控件联系起来
sv.setLlContent(llContent);
sv.setLlController(llController);
sv.setLlRefresh(llRefresh);
sv.setTvView(tvView);
sv.init();
}
}
界面xml文件
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<com.example.android_test.component.LaScrollView
android:id="@+id/sv"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<LinearLayout
android:id="@+id/llComtroller"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<LinearLayout
android:id="@+id/llContent"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
</LinearLayout>
<include
android:layout_width="fill_parent"
android:layout_height="wrap_content"
layout="@layout/list_bottom"/>
</LinearLayout>
</com.example.android_test.component.LaScrollView>
</RelativeLayout>
实现过程还是比较简单的, 代码都在这了 , 没什么其他内容了 , 源程序在 这里