Android-自定義控件之ListView下拉刷新的實(shí)現(xiàn)
自定義控件學(xué)了很久了,發(fā)現(xiàn)學(xué)了總是忘,于是打算用博客來(lái)記錄自己學(xué)習(xí)的知識(shí)點(diǎn)。
今天是自定義ListView來(lái)實(shí)現(xiàn)下拉刷新,這些文章都是借鑒慕課網(wǎng)上的視頻來(lái)寫的.
自定義一個(gè)控件,先是看它繼承于那個(gè)控件,如果我們繼承View控件的話,那得讓我們寫很多關(guān)于ListView的功能,這些東西我自己覺(jué)得很麻煩,而且也沒(méi)有那個(gè)必要因?yàn)槲覀兛梢灾苯永^承ListView,在listView的基礎(chǔ)上來(lái)加一些我們需要的東西。
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控件的測(cè)量模式
* 測(cè)量模式的產(chǎn)生方式就是如下所示
*/
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.實(shí)現(xiàn)ListView的下拉刷新(一)
要想實(shí)現(xiàn)ListView的下拉刷新,必須監(jiān)聽(tīng)ListView是否滑動(dòng)到最頂端,因此要實(shí)現(xiàn)ListView的監(jiān)聽(tīng)接口OnScrollListener,并且要監(jiān)聽(tīng)ListView的OnTouch事件。根據(jù)滑動(dòng)的情況來(lái)判斷刷新的情況。
首先我們?cè)诙x了一個(gè)成員變量來(lái)保存ListView的狀態(tài)--mState
其次定義了幾個(gè)靜態(tài)常量來(lái)表示不同的狀態(tài)
private final static int NONE = 0; // 無(wú)狀態(tài) private final static int DOWN_UPDATE = 1; // 提示下拉可以刷新 private final static int UPDATE = 2; // 提示松開(kāi)可以刷新 private final static int REFLASH = 3; // 更新
最后則是根據(jù)不同的滑動(dòng)來(lái)更改mState的狀態(tài)
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN: {
if (mFirstVisibleItem == 0) {
mIsRemark = true; // mIsRemark只是一個(gè)標(biāo)記,表示當(dāng)前可見(jiàn)的第一個(gè)Item是不是所有的Item中的第一個(gè)
mStartY = (int) ev.getY();
Log.i("main", "我進(jìn)來(lái)了");
}
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", "我來(lái)了");
}
Log.i("main", "tempY11 = " + tempY);
if(tempY <= 0 && mIsRemark)
{
Log.i("main", "我進(jìn)來(lái)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;
}
/**
*change方法主要是用來(lái)處理不同狀態(tài)下的事件
*
*/
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("松開(kāi)可以刷新!");
mTextViewTime.setVisibility(View.VISIBLE);
mTextViewTime.setText("上次更新的時(shí)間:" + 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("上次更新的時(shí)間:" + 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.實(shí)現(xiàn)ListView的下拉刷新(二)
經(jīng)過(guò)上面的過(guò)程,是可以下拉的,處理不同狀態(tài)下的事件。還有一個(gè)問(wèn)題就是刷新,也就是加載新的數(shù)據(jù)。加載刷新的操作肯定必須在UI線程中,因此ListView中必須得有一個(gè)回調(diào)接口,用來(lái)MinaActivity來(lái)實(shí)現(xiàn),并且來(lái)進(jìn)行一些操作。
回調(diào)接口:
public void setOnFlashListener(FlashListener listener)
{
this.mListener = listener;
}
public interface FlashListener
{
void reFlash();
}
回調(diào)接口的調(diào)用:
if(mState == UPDATE)
{
mState = REFLASH;
mListener.reFlash();
Log.i("main", "我來(lái)了");
}
MainActivity中回調(diào)接口的實(shí)現(xiàn)和接口方法的實(shí)現(xiàn):
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);
}
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android ViewPager畫廊效果詳解及實(shí)例
這篇文章主要介紹了Android ViewPager畫廊效果詳解及實(shí)例的相關(guān)資料,這里提供實(shí)例代碼及實(shí)現(xiàn)效果圖,具有參考價(jià)值,需要的朋友可以參考下2016-12-12
Android中的webview支持頁(yè)面中的文件上傳實(shí)例代碼
本篇文章主要介紹了Android中的webview支持頁(yè)面中的文件上傳,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-03-03
Android開(kāi)發(fā)中優(yōu)秀的app 異常處理機(jī)制
這篇文章主要介紹了Android開(kāi)發(fā)中優(yōu)秀的app 異常處理機(jī)制 的相關(guān)資料,需要的朋友可以參考下2015-12-12
Android筆記之:深入為從右向左語(yǔ)言定義復(fù)雜字串的詳解
本篇文章是對(duì)Android中為從右向左語(yǔ)言定義復(fù)雜字串進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05
實(shí)例解析Android中使用Pull解析器解析XML的方法
這篇文章主要介紹了Android中使用Pull解析器解析XML的方法,與DOM和SAX解析方式相比人們更推崇Pull,需要的朋友可以參考下2016-04-04
Android自定義可編輯、刪除的側(cè)滑LisitView
這篇文章主要為大家詳細(xì)介紹了Android自定義可編輯、刪除的側(cè)滑LisitView,感興趣的小伙伴們可以參考一下2016-07-07
詳解Android Studio無(wú)法檢測(cè)新版本問(wèn)題解決
這篇文章主要介紹了詳解Android Studio無(wú)法檢測(cè)新版本問(wèn)題解決,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-08-08
Android權(quán)限機(jī)制帶來(lái)的一些安全問(wèn)題介紹
這篇文章主要介紹了Android權(quán)限機(jī)制帶來(lái)的一些安全問(wèn)題介紹,本文講解了權(quán)限機(jī)制的缺陷和不足、樹(shù)立權(quán)限意識(shí)、越過(guò)權(quán)限機(jī)制等內(nèi)容,需要的朋友可以參考下2015-04-04

