Android Learning Note (19): Build Your own ListView

Source: Internet
Author: User

In the previous example, we wrote the UI we wanted by setting adapter's GetView (), but in a pair-oriented programming we wanted to be able to create our own ListView, For example, the name of the class Com.wei.android.learning.RatingView, as long as in XML with our own Ratingview to the ListView to replace, you can implement our style, and before in the source code to use the same simple call to the ListView.

Goals to achieve

In the Android XML file, you can call our Ratingview as follows:

<Com.wei.android.learning.RatingView <!--turned out to be a ListView and now points to our custom ListView--
Xmlns:android= "Http://schemas.android.com/apk/res/android"
Android:id= "@android: Id/list"
Android:layout_width= "Fill_parent"
android:layout_height= "Fill_parent"/>

In the Java source code, you can load our ratingview like the base listview

protected void OnCreate (Bundle savedinstancestate) {
... ...
Setcontentview (R.layout ...);
Setlistadapter (new arrayadapter<string>(this,android. R.layout.simple_list_item_1,items));
}

And our own ratingview, we in each list unit in front of the view will be added Samsung Raingbar, the back can be normal view, the use of TextView, and our previous study is similar. To do this, we need to implement the class Ratingview that inherits the ListView. The following procedure is a little more complicated than the previous example, but this approach is what we need, potentially reusing our own code and separating the UI design from the logic of the program.

Step 1: Build our ListView and point to our custom adapter

This step points our Ratingview adapter (the associated UI definition) to our custom adapter

public class ratingview  extends ListView
   //Step 1.1 overriding the constructor, We don't do special processing, call Super's constructor directly
    public Ratingview (context context) {
         super (context);
   }
    public Ratingview (Context context,attributeset attrs) {
         Super (CONTEXT,ATTRS);
   }
    Public Ratingview (context context, AttributeSet attrs, int defstyle) {
    & nbsp;   Super (context, attrs,defstyle);
   }
    //Step 1.2: By setting adapter, tie our custom adapter:ratenablewrapper, we will use this apdater to depict the UI structure of the list
    public void Setadapter (ListAdapter adapter) {
        Super.setadapter (new  ratenablewrapper ( getcontext () , adapter));
   }
}

Step 2: Implement the Custom ListAdapter interface

Let's first set up a class to store widgets for each list element. Each list element consists of two, one is the Samsung Ratingbar, and the other is the view that we pass through the layout ID.

Class viewwrapper{
ViewGroup Base;
View guts = null; We pass the view through the layout ID.
Ratingbar rate = null; Samsung Ratingbar
/* constructor, storage viewgroup*/
Viewwrapper (viewgroup base) {
This.base = base;
}
/* Get view and Settings view*/
Ratingbar Getratingbar () {
if (rate = = null)
Rate = (ratingbar) base.getchildat (0);
return rate;
}
void Setratingbar (Ratingbar rate) {
This.rate = rate;
}
/* Get Samsung Ratingbar and set up Samsung ratingbar*/
View getguts () {
if (guts = = null)
Guts=base.getchildat (1);
return guts;
}

void Setguts (View guts) {
this.guts=guts;
}
}

Let's go through the previous example by binding the ListView to a adapter in the program via Setlistadapter, which will be called to Setadapter in step 1 (listadapter adapter). We specifically implement the ListAdapter interface through the Ratenablewrapper class. This is the key to creating our own ListView.

Step 2: Implement the ListAdapter interface
Private Class Ratenablewrapperimplements ListAdapter{
//Step 2.1: Look at the parameters of Setlistadapter (which are also implemented ListAdapter) and Setadapter (), we need to save this parameter.
Context: Delivery of the displayed activity, which is often passed, of course, can also be directly through GetContext () to obtain
Rates[]: Record each star number of Samsung Ratingbar, set for our example
ListAdapter delegate = null;
Context context = NULL;
Float[] rates = NULL;
//Step 2.2: Implements the constructor, records the associated parameters, and sets the initial value of rates[].
PublicRatenablewrapper(Context context,listadapterDelegate ){
This.delegate = delegate;
This.context = context;
This.rates = new Float[delegate.getcount ()];
for (int i = 0; i < delegate.getcount (); i + +) {
This.rates[i] = 2.0f;
}
}
//Step 2.3: Implement ListAdapter interface, such as the next, directly using the parameters passed delegate, this parameter is also ListAdapter implementation class, we will focus on GetView (), the other directly call delegate processing.
public int GetCount () {
return Delegate.getcount ();
}
Public Object getItem (int position) {
return Delegate.getitem (position);
}
public long getitemid (int position) {
return Delegate.getitemid (position);
}
public int Getitemviewtype (int position) {
return Delegate.getitemviewtype (position);
}
public int Getviewtypecount () {
return Delegate.getviewtypecount ();
}
public Boolean hasstableids () {
return Delegate.hasstableids ();
}
public Boolean isEmpty () {
return Delegate.isempty ();
}
public void Registerdatasetobserver (Datasetobserver observer) {
DELEGATE.REGISTERDATASETOBSERVER (Observer);
}
public void Unregisterdatasetobserver (Datasetobserver observer) {
DELEGATE.UNREGISTERDATASETOBSERVER (Observer);
}
public Boolean areallitemsenabled () {
return delegate.areallitemsenabled ();
}
public boolean isenabled (int position) {
return delegate.isenabled (position);
}
//Step 2.4: Focus on achieving GetView
Public ViewGetView(int position,view convertview,viewgroup parent) {
Viewwrapper wrap = null; Viewwrapper is used to keep the widget for each list element, which we give later.
View row = Convertview;
//Step 2.4.1: If you have not created a view of this list unit, create it. This view is divided into two parts, the left only Samsung Ratingbar, the right is passed over the view
if (Convertview = = null) {
//Step 2.4.1.1: Set view, is horizontal linearlayout, followed by row = layout;
LinearLayout layout = new LinearLayout (context);
Layout.setorientation (linearlayout.horizontal);
(1) The first part is the Samsung Ratingbar, set the relevant properties,
Ratingbar rate = new Ratingbar (context);
Rate.setnumstars (3);
Rate.setstepsize (1.0f);
Rate.setlayoutparams (New Linearlayout.layoutparams (
Linearlayout.layoutparams.wrap_content,linearlayout.layoutparams.fill_parent));
(2) The second part is passed over the view, set the relevant properties,
View guts =Delegate.getview(position,null,parent);
Guts.setlayoutparams (New Linearlayout.layoutparams (
Linearlayout.layoutparams.wrap_content,linearlayout.layoutparams.fill_parent));
(3) placed on the LinearLayout
Layout.addview (rate);
Layout.addview (guts);

//Step 2.4.1.2: Set the trigger processing for Samsung Raingbar, in this case, we just store the clicked Star in rates[], meaning. This needs to be ratingbar this widget and index, which is position bundle, so we need to Ratingbar Settag.
Ratingbar.onratingbarchangelistener L =
New Ratingbar.onratingbarchangelistener () {
public void onratingchanged (Ratingbar ratingbar, float rating, Boolean fromuser) {
rates[(Integer) Ratingbar.gettag ()] = rating;
}
};
Rate.setonratingbarchangelistener (l);
//Step 2.4.1.3: Set the ListView UI element wrap to implement the bundle.
Wrap = new Viewwrapper (layout);
Wrap.setguts (guts);
Wrap.setraingbar (rate);
Layout.settag (wrap);
Step 2.4.1.4: Respond to step 2.4.1.2, Ratingbar to Settag ()
Rate.settag (new Integer (position));
Rate.setrating (Rates[position]);
Step 2.4.1.5, respond to step 2.4.1.1, assign a value to row
row = layout;

}else{//Step 2.4.2:If you have already created the view for this list unit. If we add log.d to track, we will find that the first screen of the 8 list elements are needed to create, but if the scroll screen, the next most of the list elements, into the Else branch. It's not clear how Android is dealing with it, it intelligently handles the UI of the list element behind it, and temporarily imagines that it intelligently handles the layout of the UI, generating widgets, but from a program perspective, these widgets are not assigned the first step of the data, Therefore, the non-UI part is involved, and it should be re-assigned on this branch safely. This should be noted.
Wrap = (Viewwrapper) convertview.gettag ();
//Step 2.4.2.1pass a view, the view may also be updated according to the scroll screen, we also have to deal with it
Wrap.setguts (Delegate.getview (Position,wrap.getguts (), parent));

//Step 2.4.2.2: Bundle Ratingbar and Postiion (Settag), set the star rating for Raingbar based on the value stored in rates[] and need to reset
Wrap.getratingbar (). Settag (new Integer (position));
Wrap.getratingbar (). setrating (Rates[position]);
}

return row;
}
}

Step 3: Experiment

Our Android Learning Note (17): Again, the ListView of the XML file in the ListView example is modified to Com.wei.android.learning.RatingView, as shown in the figure.

Discussion Issue 1: If Listitemclick is triggered

In the above main program, add a click-to-start mechanism, which is very common in list. As follows:

Getlistview (). Setonitemclicklistener (New Onitemclicklistener () {
public void Onitemclick (adapterview<?> parent, view view, int position, long ID) {
Toast.maketext (Getapplicationcontext (), items[position], Toast.length_short). Show ();
}
});

We tried to click and found no way to start the Itemlist click action. Itemlist is a layout that has a widget and a pass-through view,widget and view that can be clicked and has a better priority, so there's no need. To solve this problem, we add the following processing to the GetView ():

Layout.setdescendantfocusability (viewgroup.focus_block_descendants);

Or a description of each view in layout

Guts.setfocusable (FALSE);
Rate.setfocusable (FALSE);

As we set the view to the layout_width=wrap_content, we found that clicking on the list item blank is valid, but clicking on the widget is invalid, forcing the widget to listen for the Click event to handle

Guts.setclickable (FALSE);

So the entire view is a valid Listitemclick listening area.

Discussion Question 2: How to handle an internal widget trigger at the same time-get widget

For example, we setlistadapter in main activity (new Arrayadapter<string> (this,android. R.layout.simple_list_item_checked,items)); Checked is also available in item. In order to have a better UI experience, in GetView, we set the Guts property Layout_width is fill_parent. We hope that when ListItem is pressed, the status of the item's checked will change.

In Onitemclick () The parameter view view is actually a listitem, in this case, the Layout/row in GetView. We can add a function to the Ratingview (ListView) to return the passed view (that is, the view to the right of the layout), as follows:

public view Getmyview (view v) {
Viewwrapper wrap = (viewwrapper) v.gettag ();
return wrap.getguts ();
}

For Android. R.layout.simple_list_item_checked, this view is of type Checkedtextview and can be set using setchecked (). It doesn't seem to be a problem together, but we find that the bring of the click is not working, and the check status of the other item is somehow changed. Introduce the next discussion.

Discuss the refresh of question 3:getview () and what to note

We added the tracked log in GetView () and found that when we clicked on item, it would trigger the current screen's getview to refresh. To ensure that the refresh does not change, like Samsung Ratingbar, you need to keep the check state of the item and reset it as if it were ratingbar. For example ((Checkedtextview) wrap.getguts ()). setchecked (Checks[position]), where checkes[] we used to save the check state. So the whole display is normal. We need to refresh in GetView () for widgets with possible state changes.

Wait, this practice needs to modify our custom class, we only know to add Samsung Ratingbar, we can not preset that pass the view is what. This deviates from our original goal. We can type-detect getviewtype for this pass-through view, and if it is checkedtextview, then do the related operation.

Recall the Android UI style, actually the UI of the handheld terminal is not complicated, so we don't really need to worry so much.

RELATED links: My Andriod development related articles

Android Learning Note (19): Build Your own ListView

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.