環境:win10
編譯軟體 : AS
這裡隻講listview的基礎用法,建議先查詢widget相關知識後再來
先利用AS建立一個ListWidget,系統會自動幫你生成一個AppWidgetProvider,以及布局檔案 /xml中的list_widget_info.xml和/layout中的list_widget.xml這裡就不具體介紹了。開始我們的小例子叭
list_widget.xml中添加listview控件
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#603BA3"
android:padding="@dimen/widget_margin"
android:orientation="vertical"
android:theme="@style/ThemeOverlay.WidgetListTest.AppWidgetContainer">
<TextView
android:id="@+id/testText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:textSize="20sp"
android:text="課表"/>
<ListView
android:id="@+id/listTest"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
建立listview的子view :list_widget_item.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="horizontal"
android:layout_margin="5dp"
>
<LinearLayout
android:layout_width="0dp"
android:layout_weight="2"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/class_mc"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:layout_marginBottom="5dp"
android:textSize="18dp"
/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<ImageView
android:layout_width="15dp"
android:layout_height="15dp"
android:src="@drawable/teacher"
android:layout_marginRight="5dp"/>
<TextView
android:id="@+id/class_js"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="15dp"
android:text="***"/>
<ImageView
android:layout_width="15dp"
android:layout_height="15dp"
android:src="@drawable/place"
android:layout_marginRight="5dp"/>
<TextView
android:id="@+id/class_dd"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="10dp"
android:text="***512"/>
</LinearLayout>
</LinearLayout>
<TextView
android:id="@+id/class_sj"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
android:text="17:00-18:40"
android:textColor="@color/cardview_light_background"
android:gravity="center"
/>
</LinearLayout>
建立一個list的服務擴充卡ListviewService
class ListViewService : RemoteViewsService() {
override fun onGetViewFactory(intent: Intent?): RemoteViewsFactory? {
return ListRemoteViewsFactory(this.applicationContext, intent)
}
private class ListRemoteViewsFactory (context: Context, intent: Intent?): RemoteViewsFactory{
private var mContext: Context? = context
var appWidgetId = Integer.valueOf(intent?.getData()?.getSchemeSpecificPart())- ListWidget().m //得到原來的widgetId
private val mList = ArrayList<String>()
override fun onCreate() {
mList.add(Date().toString())//擷取系統的時間 相當于檢測該擴充卡是否正常運作
mList.add("計算機作業系統")
mList.add("計算機作業系統")
mList.add("計算機作業系統")
mList.add("計算機作業系統")
}
override fun onDataSetChanged() {
mList.clear()
mList.add(Date().toString())//擷取系統的時間 相當于檢測該擴充卡是否正常運作
mList.add("計算機作業系統")
mList.add("計算機作業系統")
mList.add("計算機作業系統")
mList.add("計算機作業系統")
}
override fun onDestroy() {
mList.clear()
}
override fun getCount(): Int {
return mList.size
}
override fun getViewAt(position: Int): RemoteViews? {
val views = RemoteViews(mContext!!.packageName, R.layout.list_widget_item)
views.setTextViewText(R.id.class_mc,mList[position])
Log.d("momo",mList[position])
return views
}
/* 在更新界面的時候如果耗時就會顯示 正在加載... 的預設字樣,但是你可以更改這個界面
* 如果傳回null 顯示預設界面
* 否則 加載自定義的,傳回RemoteViews
*/
override fun getLoadingView(): RemoteViews? {
return null
}
override fun getViewTypeCount(): Int {
return 1
}
override fun getItemId(position: Int): Long {
return position.toLong()
}
override fun hasStableIds(): Boolean {
return false
}
}
}
- RemoteViewsService : 是一個遠端的服務擴充卡 可以請求RemoteViews,管理RemoteViews的服務.
- RemoteViewsFactory : 提供了RemoteViewsFactory用于填充遠端集合視圖。
- onDataSetChanged():是用于更新listview中的資料的
- getViewAt(position: Int):用于填充子view
在AppWidgetProvider的update()中設定adapter
class ListWidget : AppWidgetProvider() {
var m=(0..1000).random() //随機數
override fun onUpdate(
context: Context,
appWidgetManager: AppWidgetManager,
appWidgetIds: IntArray
) {
for (i in appWidgetIds){
// There may be multiple widgets active, so update all of them
val views = RemoteViews(context.packageName, R.layout.list_widget)
views.setTextViewText(R.id.testText, "課表")
val adapter = Intent(context, ListViewService::class.java)//建立擴充卡
adapter.setData(Uri.fromParts("content",i.toString()+m.toString(),null))//加上一個随機數讓RemoteViewsFactory認為是一個新的widgetid而重新建立新工廠RemoteViewsFactory
views.setRemoteAdapter(R.id.listTest, adapter) //為list綁定adapter
views.setEmptyView(R.id.listTest,android.R.id.empty)
val mComponentName = ComponentName(context, ListWidget::class.java)
appWidgetManager.updateAppWidget(mComponentName, views)
}
}
override fun onEnabled(context: Context) {
// Enter relevant functionality for when the first widget is created
}
override fun onDisabled(context: Context) {
// Enter relevant functionality for when the last widget is disabled
}
}
internal fun updateAppWidget(
context: Context,
appWidgetManager: AppWidgetManager,
appWidgetId: Int
) {
val widgetText = context.getString(R.string.appwidget_text)
// Construct the RemoteViews object
val views = RemoteViews(context.packageName, R.layout.list_widget)
// Instruct the widget manager to update the widget
appWidgetManager.updateAppWidget(appWidgetId, views)
}
為什麼需要重新建立工廠: 是因為遠端服務擴充卡會緩存所有widgetid的工廠,是以當你需要更新listview内容而發送請求時,服務擴充卡并不會為你重新建立工廠進而更新内容。這裡還有一種方案:就是調用notifyAppWidgetViewDataChanged()方法,但是有時會沒有效果,我也不知道為什麼。
m是一個公開的随機數