??自定義控件學了很久了者祖,發(fā)現學了總是忘,于是打算用博客來記錄自己學習的知識點屁商。
??今天是自定義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的下拉刷新僻族,必須監(jiān)聽ListView是否滑動到最頂端,因此要實現ListView的監(jiān)聽接口OnScrollListener屡谐,并且要監(jiān)聽ListView的OnTouch事件述么。根據滑動的情況來判斷刷新的情況。
??首先我們在定義了一個成員變量來保存ListView的狀態(tài)--mState
??其次定義了幾個靜態(tài)常量來表示不同的狀態(tài)
private final static int NONE = 0; // 無狀態(tài)
private final static int DOWN_UPDATE = 1; // 提示下拉可以刷新
private final static int UPDATE = 2; // 提示松開可以刷新
private final static int REFLASH = 3; // 更新
最后則是根據不同的滑動來更改mState的狀態(tài):
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方法主要是用來處理不同狀態(tài)下的事件<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的下拉刷新(二)
??經過上面的過程度秘,是可以下拉的,處理不同狀態(tài)下的事件。還有一個問題就是刷新剑梳,也就是加載新的數據唆貌。加載刷新的操作肯定必須在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);
}