作為一個剛畢業的大學生,我要提醒自己時時刻刻要學習。
最近做listview看到很久以前的一個demo,高手如雲啊,我們就只有好好加油了。
這是索尼公司的一個員工寫的學習部落格,由於本人英文能力有限是按照自己的理解來的,可能有些地方是錯誤的,還請各位勘正。
原文連結
The standard Android list view has support for quite a lot of things and covers almost all the use-cases you could think of. However, the look of the list is quite ordinary and while you can do some things by extending it, you will not be able to do that much in the end. Another disadvantage of the standard ListView is the lack of good physics (and the ability to change it). Therefore, if you want your UI to be a bit less ordinary looking, you simply need to implement your own view.
android官方提供的ListView已經支援了好多功能和滿足了幾乎全部的你可以想到的需求。但是,Listview的外觀在拓展時還是顯得很一般,且我們也不能在最後能做什麼。另一個標準的LIstview缺乏好的控制。因此,若是你不想的你的UI顯得很福士,那就要你來實現你自己的View。
Hello AdapterView
Since we’re aiming for a list (that will show other views) we need to extend a ViewGroup and the most fitting of those are AdapterView. (The reason, or rather one reason, we’re not extending AbsListView is that it will not allow us to do bounce effects on the list.) So let’s start by creating a new Android project and create a class, MyListView, that extends AdapterView<Adapter>. AdapterView has four abstract methods that we need to implement: getAdapter(), setAdapter(), getSelectedView() and setSelection(). getAdapter() and setAdapter() are straight forward to implement. The other two will for the moment just throw an exception.
因為我們是要展示一系列資料,我們需要自己來拓展ViewGroup並且最合適的是AdapterView了。(不拓展AbsListview的一個理由就是它不允許我們在listview的每一個邊界上來設定一些特效。)就讓我們來建立一個ANdroid工程和一個繼承了AdapterView<Adapter>. Mylistview類。AdapterView<Adapter>這個類有四個我們必須要實現的函數,那就是getAdapter(), setAdapter(), getSelectedView() and setSelection(). 其中前兩個就直接來實現,後兩個就直接拋出異常。
MyListView = setSelection( UnsupportedOperationException("Not supported" UnsupportedOperationException("Not supported"
The only thing here worth mentioning is the setAdapter method. When we get a new adapter we clear all the views we might have had previously and then we request a layout to get and position the views from the adapter. If we at this point create a test activity and an adapter with some fake data and use our new view, we will not get anything on the screen. This is because if we want to get something on the screen we need to override the onLayout() method.
這個僅有的我們需要注意的是setAdapter方法。當我們得到一個新的adapter對象,我們要清除掉前面添加的所有的view,並且為每一個在Adapter裡的view請求重新布局。如果此時我們建立一個測試的Activity和一個Adapter
用一些類比資料和新的視圖View,在螢幕上會什麼也不會顯示,這是因為,要想在螢幕上顯示,我們必須實現OnLayout方法。
Showing our first views
It is in onLayout where we get the views from the adapter and add them as child views.
就是在onLayout方法裡,我們從Adapter對象裡得到了每個view,並把他們都加到list視圖裡。
onLayout( changed, left, top, right, (mAdapter == (getChildCount() == 0 position = 0 bottomEdge = 0 (bottomEdge< getHeight() && position<= mAdapter.getView(position, , +=++
So, what happens here? First a call to super and a null check are performed, and then we continue with the actual code. If we haven’t added any children yet, we start by doing that. The while statement loops through the adapter until we’ve added enough views to cover the screen. When we get a view from the adapter, we start by adding it as a child and then we need to measure it in order for the view to get it’s correct size. After we’ve added all the views, we position them in the correct place.
嗯,這是幹嘛呢?首先是調用super()函數,檢查adapter是否為空白,若不是就執行相關代碼。若是沒有子view可加入到listview中,有子view時就通過Adapter來迴圈擷取子view知道我們將所有的子view填充到螢幕中。當我們從adapter擷取一個view時,我們就將他加入到listview中並計算擷取其正確的尺寸,而後就將他們有序地放到正確的位置上。
= (params == = -1, params, itemWidth =| top = 0 ( index = 0; index< getChildCount(); index++= width = height = left = (getWidth() - width) / 2+ width, top ++=
The code here is straight forward and self-explanatory so I won’t go into details. I’ve taken some shortcuts when measuring the child view but the code works quite well in most cases. positionItems() starts at the top (0) and layouts the child views one after the other without any padding between them. Also worth noting is that we’re ignoring the possible padding that the list can have.
Scrolling
If we run this code we will now get something on the screen. However, it’s not very interactive. It does not scroll when we touch the screen and we can’t click on any item. To get touch working in the list we need to overrideonTouchEvent().
The touch logic for just scrolling is pretty simple. When we get a down event, we save both the position of the down event and the position of the list. We will use the top of the first item to represent the list position. When we get a move event we calculate how far we are from the down event and then re-position the list using the difference in distance from the start position. If we have
no child views, we just return false.
(getChildCount() == 0 = (= getChildAt(0 scrolledDistance = ()event.getY() -= mListTopStart +
The position of the list is now determined by mListTop and whenever it changes we need to request a layout in order to actually re-position the views. Our previous implementation of positionItems() always started to layout from 0. Now we need to change it so that it starts from mListTop.
If we try this out now the scrolling will work fine but we can also spot some obvious problems with our list. First, the scrolling has no limits so we can scroll the list so that all items are outside of the screen. We will need some kind of limits check to prevent us from doing that. Second, if we scroll down we also see that only the items that we had from the beginning are displayed. No new items are displayed even though the adapter contains more items. We postpone the fix of the first problem to a later tutorial but let’s fix the second problem right away.