以下是我自己花功夫編寫了一種非常簡(jiǎn)單的下拉刷新實(shí)現(xiàn)方案,現(xiàn)在拿出來(lái)和大家分享一下。相信在閱讀完本篇文章之后,大家都可以在自己的項(xiàng)目中一分鐘引入下拉刷新功能 最近項(xiàng)目中需要用到ListView下拉刷新的功能,一開始想圖省事,在網(wǎng)上直接找一個(gè)現(xiàn)成的,可是嘗試了網(wǎng)上多個(gè)版本的下拉刷新之后發(fā)現(xiàn)效果都不 怎么理想。有些是因?yàn)楣δ懿煌暾蛴蠦ug,有些是因?yàn)槭褂闷饋?lái)太復(fù)雜,十全十美的還真沒(méi)找到。因此我也是放棄了在網(wǎng)上找現(xiàn)成代碼的想法,自己花功夫編寫 了一種非常簡(jiǎn)單的下拉刷新實(shí)現(xiàn)方案,現(xiàn)在拿出來(lái)和大家分享一下。相信在閱讀完本篇文章之后,大家都可以在自己的項(xiàng)目中一分鐘引入下拉刷新功能。首先講一下實(shí)現(xiàn)原理。這里我們將采取的方案是使用組合View的方式,先自定義一個(gè)布局繼承自LinearLayout,然后在這個(gè)布局中加入下拉 頭和ListView這兩個(gè)子元素,并讓這兩個(gè)子元素縱向排列。初始化的時(shí)候,讓下拉頭向上偏移出屏幕,這樣我們看到的就只有ListView了。然后對(duì) ListView的touch事件進(jìn)行監(jiān)聽,如果當(dāng)前ListView已經(jīng)滾動(dòng)到頂部并且手指還在向下拉的話,那就將下拉頭顯示出來(lái),松手后進(jìn)行刷新操 作,并將下拉頭隱藏。原理示意圖如下:那我們現(xiàn)在就來(lái)動(dòng)手實(shí)現(xiàn)一下,新建一個(gè)項(xiàng)目起名叫PullToRefreshTest,先在項(xiàng)目中定義一個(gè)下拉頭的布局文件pull_to_refresh/apk/res/android"xmlns:tools="schemas/tools"android:id="@+id/pull_to_refresh_head"android:layout_width="fill_parent"android:layout_height="60dip" LinearLayoutandroid:layout_width="200dip"android:layout_height="60dip"android:layout_centerInParent="true"android:orientation="horizontal" RelativeLayoutandroid:layout_width="0dip"android:layout_height="60dip"android:layout_weight="3"ImageView android:id="@+id/arrow"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerInParent="true"android:src="@drawable/arrow"/ProgressBar android:id="@+id/progress_bar"android:layout_width="30dip"android:layout_height="30dip"android:layout_centerInParent="true"android:visibility="gone"http://RelativeLayoutLinearLayoutandroid:layout_width="0dip"android:layout_height="60dip"android:layout_weight="12"android:orientation="vertical" TextViewandroid:id="@+id/description"android:layout_width="fill_parent"android:layout_height="0dip"android:layout_weight="1"android:gravity="center_horizontalbottom"android:text="@string/pull_to_refresh" /TextViewandroid:id="@+id/updated_at"android:layout_width="fill_parent"android:layout_height="0dip"android:layout_weight="1"android:gravity="center_horizontaltop"android:text="@string/updated_at" //LinearLayout/LinearLayout/RelativeLayout 在這個(gè)布局中,我們包含了一個(gè)下拉指示箭頭,一個(gè)下拉狀態(tài)文字提示,和一個(gè)上次更新的時(shí)間。當(dāng)然,還有一個(gè)隱藏的旋轉(zhuǎn)進(jìn)度條,只有正在刷新的時(shí)候我們才會(huì)將它顯示出來(lái)。布局中所有引用的字符串我們都放在stringsmit();new HideHeaderTask()/apk/res/android"xmlns:tools="schemas/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity" com.example.pulltorefreshtest.RefreshableViewandroid:id="@+id/refreshable_view"android:layout_width="fill_parent"android:layout_height="fill_parent" ListViewandroid:id="@+id/list_view"android:layout_width="fill_parent"android:layout_height="fill_parent" /ListView/com.example.pulltorefreshtest.RefreshableView/RelativeLayout 可以看到,我們?cè)谧远x的RefreshableView中加入了一個(gè)ListView,這就意味著給這個(gè)ListView加入了下拉刷新的功能,就是這么簡(jiǎn)單!然后我們?cè)賮?lái)看一下程序的主Activity,打開或新建MainActivity,加入如下代碼:復(fù)制代碼 代碼如下: public class MainActivity extends Activity {RefreshableView refreshableView;ListView listView;ArrayAdapterString adapter;String[] items = { "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L" };@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);requestWindowFeature(Window.FEATURE_NO_TITLE);setContentView(R.layout.activity_main);refreshableView = (RefreshableView) findViewById(R.id.refreshable_view);listView = (ListView) findViewById(R.id.list_view);adapter = new ArrayAdapterString(this, android.R.layout.simple_list_item_1, items);listView.setAdapter(adapter);refreshableView.setOnRefreshListener(new PullToRefreshListener() {@Overridepublic void onRefresh() {try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}refreshableView.finishRefreshing();}}, 0);}} 可 以看到,我們通過(guò)調(diào)用RefreshableView的setOnRefreshListener方法注冊(cè)了一個(gè)監(jiān)聽器,當(dāng)ListView正在刷新時(shí)就 會(huì)回調(diào)監(jiān)聽器的onRefresh方法,刷新的具體邏輯就在這里處理。而且這個(gè)方法已經(jīng)自動(dòng)開啟了線程,可以直接在onRefresh方法中進(jìn)行耗時(shí)操 作,比如向服務(wù)器請(qǐng)求最新數(shù)據(jù)等,在這里我就簡(jiǎn)單讓線程睡眠3秒鐘。另外在onRefresh方法的最后,一定要調(diào)用RefreshableView中的 finishRefreshing方法,這個(gè)方法是用來(lái)通知RefreshableView刷新結(jié)束了,不然我們的ListView將一直處于正在刷新的 狀態(tài)。不知道大家有沒(méi)有注意到,setOnRefreshListener這個(gè)方法其實(shí)是有兩個(gè)參數(shù)的,我們剛剛也是傳入了一個(gè)不起眼的 0。那這第二個(gè)參數(shù)是用來(lái)做什么的呢?由于RefreshableView比較智能,它會(huì)自動(dòng)幫我們記錄上次刷新完成的時(shí)間,然后下拉的時(shí)候會(huì)在下拉頭中 顯示距上次刷新已過(guò)了多久。這是一個(gè)非常好用的功能,讓我們不用再自己手動(dòng)去記錄和計(jì)算時(shí)間了,但是卻存在一個(gè)問(wèn)題。如果當(dāng)前我們的項(xiàng)目中有三個(gè)地方都使 用到了下拉刷新的功能,現(xiàn)在在一處進(jìn)行了刷新,其它兩處的時(shí)間也都會(huì)跟著改變!因?yàn)樗⑿峦瓿傻臅r(shí)間是記錄在配置文件中的,由于在一處刷新更改了配置文件, 導(dǎo)致在其它兩處讀取到的配置文件時(shí)間已經(jīng)是更改過(guò)的了。那解決方案是什么?就是每個(gè)用到下拉刷新的地方,給setOnRefreshListener方法 的第二個(gè)參數(shù)中傳入不同的id就行了。這樣各處的上次刷新完成時(shí)間都是單獨(dú)記錄的,相互之間就不會(huì)再有影響。好了,全部的代碼都在這里了,讓我們來(lái)運(yùn)行一下,看看效果吧。效果看起來(lái)還是非常不錯(cuò)的。我們最后再來(lái)總結(jié)一下,在項(xiàng)目中引入ListView下拉刷新功能只需三步:1. 在Activity的布局文件中加入自定義的RefreshableView,并讓ListView包含在其中。2. 在Activity中調(diào)用RefreshableView的setOnRefreshListener方法注冊(cè)回調(diào)接口。3. 在onRefresh方法的最后,記得調(diào)用RefreshableView的finishRefreshing方法,通知刷新結(jié)束。從此以后,在項(xiàng)目的任何地方,一分鐘引入下拉刷新功能妥妥的。好了,今天的講解到此結(jié)束,有疑問(wèn)的朋友請(qǐng)?jiān)谙旅媪粞?。源碼下載,請(qǐng)點(diǎn)擊這里
潁州網(wǎng)站建設(shè)公司創(chuàng)新互聯(lián),潁州網(wǎng)站設(shè)計(jì)制作,有大型網(wǎng)站制作公司豐富經(jīng)驗(yàn)。已為潁州上千余家提供企業(yè)網(wǎng)站建設(shè)服務(wù)。企業(yè)網(wǎng)站搭建\外貿(mào)營(yíng)銷網(wǎng)站建設(shè)要多少錢,請(qǐng)找那個(gè)售后服務(wù)好的潁州做網(wǎng)站的公司定做!
在UI中經(jīng)常會(huì)使用到下拉列表,在android控件中有兩個(gè)下拉列表控件:
在xml中添加控件的使用:
主題:
這些都沒(méi)有達(dá)到我要的效果:
android:entries // 傳入的是values文件夾下的arrayx.xml內(nèi)的數(shù)據(jù)
android:spinnerMode //顯示模式有popmenu和dialog兩種
android:prompt //當(dāng)顯示模式為dialog時(shí)生效,作用為顯示dialog的標(biāo)題內(nèi)容
最近在開發(fā)中想要實(shí)現(xiàn)一個(gè)下拉通知欄的功能,但是在6.0上使用方法下拉,展開動(dòng)畫十分緩慢,剛好在Nova launcher中,也實(shí)現(xiàn)了下拉通知欄,而且在6.0上提示說(shuō)獲取root權(quán)限,變通的解決這個(gè)問(wèn)題,在酷安開發(fā)者群有朋友提到說(shuō)可以在獲取root權(quán)限后使用shell模擬觸摸事件來(lái)實(shí)現(xiàn)這個(gè)方法,測(cè)試以后發(fā)現(xiàn)確實(shí)可行。
調(diào)用如下指令模擬手勢(shì)實(shí)現(xiàn)下拉:
adb shell input swipe 100 1 100 500 300 模擬滑動(dòng)事件 在x 100 y 1的位置滑動(dòng)到 x 100 y 500的位置 歷時(shí)300毫秒
此時(shí)通知欄并不會(huì)完全展開,解決方法也非常簡(jiǎn)單,再模擬一次點(diǎn)擊事件,點(diǎn)擊剛剛沒(méi)有完全展開的狀態(tài)欄即可:
adb shell input tap 100 100 模擬點(diǎn)擊事件,點(diǎn)擊了一下x 100 y 100的位置
這樣通知欄就完全展開了
Android的下拉列表是用Spinner 這個(gè)類來(lái)實(shí)現(xiàn)的。
Spinner的使用(分別使用ArrayAdapter和自定義Adapter實(shí)現(xiàn)),使用ArrayAdapter進(jìn)行適配數(shù)據(jù):
1:首先定義一個(gè)布局文件:
LinearLayout xmlns:android=""
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
Spinner
android:id="@+id/spinner1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/
/LinearLayout
2:建立數(shù)據(jù)源,使用數(shù)組,這些數(shù)據(jù)將會(huì)在Spinner下來(lái)列表中進(jìn)行顯示:
?xml version="1.0" encoding="utf-8"?
resources
string-array name="spinnername"
item北京/item
item上海 /item
item廣州/item
item深圳/item
/string-array
/resources
3:接著在Activity中加入如下的代碼(使用了系統(tǒng)定義的下拉列表的布局文件,當(dāng)然也可以自定義)
// 初始化控件
mSpinner = (Spinner) findViewById(R.id.spinner1);
// 建立數(shù)據(jù)源
String[] mItems = getResources().getStringArray(R.array.spinnername);
// 建立Adapter并且綁定數(shù)據(jù)源
ArrayAdapterString _Adapter=new ArrayAdapterString(this,android.R.layout.simple_spinner_item, mItems);
//綁定 Adapter到控件
mSpinner.setAdapter(_Adapter);
在某個(gè)APP中,發(fā)現(xiàn)下拉通知欄的時(shí)候,正在播放的視頻會(huì)暫停,于是有點(diǎn)好奇這段操作是不是在生命周期中實(shí)現(xiàn)的。在網(wǎng)上眾多關(guān)于Activity生命周期的討論中,很多人認(rèn)為 onPause() 和 onStop() 的區(qū)別就是“部分遮擋”和“全部遮擋”,那按照這個(gè)猜測(cè)來(lái)分析一下這個(gè)過(guò)程:
首先,通知欄下拉一點(diǎn)點(diǎn),符合一般描述中“Activity被部分遮擋”—— onPause()
然后,通知欄完全落下之后,“Activity被全部遮擋”—— onStop()
于是自己寫了一個(gè)實(shí)例來(lái)驗(yàn)證:
啟動(dòng)APP時(shí),毫無(wú)疑問(wèn),調(diào)用了 onCreate() → onStart() → onResume() ;
完全下拉通知欄,然后上拉通知欄,發(fā)現(xiàn)沒(méi)有日志打印,說(shuō)明 下拉通知欄對(duì)Activity的生命周期沒(méi)有影響 。
經(jīng)過(guò)測(cè)試不難發(fā)現(xiàn),在Activity中彈出AlertDialog、Toast時(shí),Activity的 onPause() 并沒(méi)有調(diào)用;筆者還嘗試在MIUI系統(tǒng)中喚醒小愛(ài)同學(xué),發(fā)現(xiàn) onPause() 仍然沒(méi)有被調(diào)用。
但是在以下特殊的情況下, onPause() 會(huì)被調(diào)用:
跑去看文檔發(fā)現(xiàn)了如下信息:
發(fā)現(xiàn)了 onPause() 和Activity的奇妙聯(lián)系,就不難理解之前為什么沒(méi)有被調(diào)用的問(wèn)題了。
查看AlertDialog和Toast的源碼,可以發(fā)現(xiàn)它們顯示的原理,都是通過(guò) WindowManager.addView() 來(lái)顯示的。也就是說(shuō),AlertDialog和Toast可以看做是當(dāng)前Activity的一部分View,當(dāng)然也不會(huì)對(duì)Activity的生命周期構(gòu)成影響。
因此, onPause() 是否調(diào)用的關(guān)鍵就是,是否有另一個(gè)Activity參與進(jìn)來(lái)了。
而網(wǎng)上流傳甚廣的 onPause() 和 onStop() 調(diào)用中提到的“遮擋”,應(yīng)該修正為 “被Activity遮擋”
至于官方文檔中提到的, onPause() 之后會(huì)調(diào)用 onStop() 或者 onResume() ,前者很好理解,一般的退出、新啟動(dòng)一個(gè)全屏Activity、鎖屏、返回HOME等操作都是這種情況;至于后者,筆者能想到的情況就是,彈出部分遮擋的Activity類型的對(duì)話框,然后按返回鍵。
圖樣:
實(shí)現(xiàn)方式:
1、水平布局一個(gè)TextView和一個(gè)ImageView(小黑箭頭)
2、實(shí)現(xiàn)點(diǎn)擊ImageView的單擊事件,彈出PopupWindow
3、PopupWindow中實(shí)現(xiàn)下拉列表
關(guān)鍵代碼示例:
1、布局
LinearLayout?android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
TextView/
ImageView?/
/LinearLayout
2、單擊事件
image.setBackgroundResource(R.drawable.gerendang_jiantou);??
image.setOnClickListener(new?OnClickListener()?{??
public?void?onClick(View?v)?{
//彈出popupwindow
}
});
3、pupupwindow相關(guān)代碼
ListView?lv?=?new?ListView(this);
adapter?=?new?OptionsAdapter(context,?datas);?//?根據(jù)數(shù)據(jù),設(shè)置下拉框顯示??
list.setAdapter(adapter);??
/**?
*?兩種不同長(zhǎng)度的下拉框,主要是為了適應(yīng)屏幕的大小?
*/??
if?(p_width??0)?{??
pWindow?=?new?PopupWindow(v,?par.getWidth(),?150);??
}?else?{??
pWindow?=?new?PopupWindow(v,?par.getWidth(),?300);??
}??
pWindow.setFocusable(true);??//能夠焦點(diǎn)獲得
pWindow.setBackgroundDrawable(new?BitmapDrawable());??//設(shè)置背景
pWindow.setOutsideTouchable(true);??//外部點(diǎn)擊關(guān)閉
pWindow.update();??//更新位置
pWindow.showAsDropDown(text);//顯示下拉列表