自定义控件学了很久了,发现学了总是忘,于是打算用博客来记录自己学习的知识点。
今天是自定义ListView来实现下拉刷新,这些文章都是借鉴慕课网上的视频来写的.
自定义一个控件,先是看它继承于那个控件,如果我们继承View控件的话,那得让我们写很多关于ListView的功能,这些东西我自己觉得很麻烦,而且也没有那个必要因为我们可以直接继承ListView,在listView的基础上来加一些我们需要的东西。
1.向ListView加Header布局
private void initView(Context context)
{
mLayoutInflater = LayoutInflater.from(context);
mHeaerView = mLayoutInflater.inflate(R.layout.header_layout, null, false);
addHeaderView(mHeaerView);
}
2.隐藏Header布局
private void initView(Context context) {
mLayoutInflater = LayoutInflater.from(context);
mHeaerView = mLayoutInflater.inflate(R.layout.header_layout, null, false);
measureView(mHeaerView);
mHeaderViewHeight = mHeaerView.getMeasuredHeight();
setHeaderViewHeightPadding(mHeaderViewHeight);
Log.i("main", mHeaderViewHeight + "");
addHeaderView(mHeaerView);
}
private void measureView(View view)
{
ViewGroup.LayoutParams lp = view.getLayoutParams();
if(lp == null)
{
lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
}
//mHeaerView.measure(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
/**
* width 和height里面包含的不仅仅有View的宽和高,还有View控件的测量模式
* 测量模式的产生方式就是如下所示
*/
int width = ViewGroup.getChildMeasureSpec(0,0,lp.width);
int height = 0;
int tempHeight = lp.height;
if(tempHeight > 0)
{
height = MeasureSpec.makeMeasureSpec(tempHeight, MeasureSpec.EXACTLY);
}
view.measure(width, height);
}
private void setHeaderViewHeightPadding(int padding) {
mHeaerView.setPadding(mHeaerView.getPaddingLeft(), -padding, mHeaerView.getPaddingRight(), mHeaerView.getPaddingBottom());
mHeaerView.invalidate();
}
3.实现ListView的下拉刷新(一)
要想实现ListView的下拉刷新,必须监听ListView是否滑动到最顶端,因此要实现ListView的监听接口OnScrollListener,并且要监听ListView的OnTouch事件。根据滑动的情况来判断刷新的情况。
首先我们在定义了一个成员变量来保存ListView的状态--mState
其次定义了几个静态常量来表示不同的状态
private final static int NONE = 0; // 无状态
private final static int DOWN_UPDATE = 1; // 提示下拉可以刷新
private final static int UPDATE = 2; // 提示松开可以刷新
private final static int REFLASH = 3; // 更新
最后则是根据不同的滑动来更改mState的状态:
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN: {
if (mFirstVisibleItem == 0) {
mIsRemark = true; // mIsRemark只是一个标记,表示当前可见的第一个Item是不是所有的Item中的第一个
mStartY = (int) ev.getY();
Log.i("main", "我进来了");
}
break;
}
case MotionEvent.ACTION_MOVE: {
onMove(ev);
tempY = (int) (ev.getY() - mStartY);
Log.i("main", "tempY = " + tempY);
break;
}
case MotionEvent.ACTION_UP: {
if(mState == DOWN_UPDATE)
{
mState = NONE;
}
if(mState == UPDATE)
{
mState = REFLASH;
mListener.reFlash();
Log.i("main", "我来了");
}
Log.i("main", "tempY11 = " + tempY);
if(tempY <= 0 && mIsRemark)
{
Log.i("main", "我进来le");
mState = NONE;
}
change();
break;
}
}
return super.onTouchEvent(ev);
}
private void onMove(MotionEvent ev) {
if (mIsRemark) {
if (ev.getY() - mStartY > 0) {
int dy = (int) (ev.getY() - mStartY);
if (dy > mHeaderViewHeight + 20) {
mState = UPDATE;
} else {
mState = DOWN_UPDATE;
}
setHeaderViewHeightPadding(mHeaderViewHeight - dy);
change();
}
return;
}
return;
}
/**<br> *change方法主要是用来处理不同状态下的事件<br> *<br> */
private void change() {
initChildView();
RotateAnimation ani = new RotateAnimation(0, 180, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f);
ani.setDuration(500);
ani.setFillAfter(true);
RotateAnimation ani1 = new RotateAnimation(180, 0, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f);
ani1.setDuration(500);
ani1.setFillAfter(true);
if (mState == UPDATE)
{
mProgressBar.setVisibility(View.GONE);
mImageView.setVisibility(View.VISIBLE);
mImageView.clearAnimation();
mImageView.setAnimation(ani);
mTextViewFlash.setText("松开可以刷新!");
mTextViewTime.setVisibility(View.VISIBLE);
mTextViewTime.setText("上次更新的时间:" + mUpdateTime);
}
if (mState == DOWN_UPDATE)
{
mProgressBar.setVisibility(View.GONE);
mImageView.setVisibility(View.VISIBLE);
mTextViewTime.setVisibility(View.VISIBLE);
mImageView.clearAnimation();
mImageView.setAnimation(ani1);
mTextViewFlash.setText("下拉可以刷新");
mTextViewTime.setText("上次更新的时间:" + mUpdateTime);
}
if (mState == REFLASH)
{
setHeaderViewHeightPadding(10);
mProgressBar.setVisibility(View.VISIBLE);
mImageView.setVisibility(View.GONE);
mTextViewTime.setVisibility(View.GONE);
mTextViewFlash.setText("正在刷新...");
mImageView.clearAnimation();
}
if(mState == NONE)
{
Log.i("main", "workspace");
setHeaderViewHeightPadding(mHeaderViewHeight);
mIsRemark = false;
mProgressBar.setVisibility(View.GONE);
mImageView.setVisibility(View.VISIBLE);
mImageView.setAnimation(ani1);
}
}
private void initChildView()
{
if(mTextViewFlash == null)
{
mTextViewFlash = (TextView) mHeaerView.findViewById(R.id.id_textView_Flash);
}
if(mTextViewTime == null)
{
mTextViewTime = (TextView) mHeaerView.findViewById(R.id.id_textView_Time);
}
if(mImageView == null)
{
mImageView = (ImageView) mHeaerView.findViewById(R.id.id_imagView);
}
if(mProgressBar == null)
{
mProgressBar = (ProgressBar) mHeaerView.findViewById(R.id.id_progressbar);
}
}
4.实现ListView的下拉刷新(二)
经过上面的过程,是可以下拉的,处理不同状态下的事件。还有一个问题就是刷新,也就是加载新的数据。加载刷新的操作肯定必须在UI线程中,因此ListView中必须得有一个回调接口,用来MinaActivity来实现,并且来进行一些操作。
回调接口:
public void setOnFlashListener(FlashListener listener)
{
this.mListener = listener;
}
public interface FlashListener
{
void reFlash();
}
回调接口的调用:
if(mState == UPDATE)
{
mState = REFLASH;
mListener.reFlash();
Log.i("main", "我来了");
}
MainActivity中回调接口的实现和接口方法的实现:
mListView.setOnFlashListener(new FlashListView.FlashListener() {
@Override
public void reFlash() {
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
addDatas();
loadDatas();
mListView.reFalshComplete();
}
}, 5000);
}
});
private void addDatas()
{
int i = mDatas.size();
for(int j = i; j < i + 10; j++)
{
mDatas.add(new Bean("Title" + j, "Content" + j, R.mipmap.ic_launcher));
}
myAdapter.dataChange(mDatas);
}
private void loadDatas()
{
mListView.setAdapter(myAdapter);
}