Android learning notes (19th): Create your own ListView

Source: Internet
Author: User

In the previous example, we set getview () of the adapter to write the UI we want. However, in Object-Oriented Programming, we want to create our own listview, for example, the class name is com. wei. android. learning. ratingview, as long as we replace listview with our own ratingview in XML, we can implement our style, and simply call listview in the source code.

Goals

In the android XML file, you can call our ratingview as follows:

<Com. wei. android. learning. RatingView
<! -- Originally ListView, now pointing 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 just like the basic listview.

Protected void onCreate (Bundle savedInstanceState ){
......
SetContentView (R. layout ......);
SetListAdapter (New ArrayAdapter <String>(This, android. R. layout. simple_list_item_1, items));
}

In our own ratingview, we will add a Samsung raingbar in front of the view in each list unit, which can be followed by a general view using textview, which is similar to our previous learning. Therefore, we need to implement the class ratingview that inherits the listview. The following process is a little more complex than the previous example, but this method is what we need. We may reuse our own code and separate the uidesign from the logic processing of the program.

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

In this step, point the adapter (related UI definition) of our ratingview to our custom adapter.

Public class RatingViewExtends ListView{
// Step 1.1 rewrite the constructor. We can directly call the super constructor without special processing.
Public ratingview (context ){
Super (context );
}
Public ratingview (context, attributeset attrs ){
Super (context, attrs );
}
Public ratingview (context, attributeset attrs, int defstyle ){
Super (context, attrs, defstyle );
}
// Step 1.2: bind the custom adapter ratenablewrapper by setting the adapter. We will use this apdater to describe the list UI structure.
Public void setadapter (listadapter adapter ){
Super. setadapter (NewRatenableWrapper(GetContext (), Adapter ));
}
}

Step 2: implement the custom ListAdapter Interface

We first set a class to store the widgets of each list element. Each list element is composed of two elements: Samsung ratingbar and view passed by layout ID.

Class ViewWrapper {
ViewGroup base;
View guts = null; // View passed by layout Id
RatingBar rate = null; // Samsung RatingBar
/* Constructor, storing ViewGroup */
ViewWrapper (ViewGroup base ){
This. base = base;
}
/* Get and set the View */
RatingBar getRatingBar (){
If (rate = null)
Rate = (RatingBar) base. getChildAt (0 );
Return rate;
}
Void setRatingBar (RatingBar rate ){
This. rate = rate;
}
/* Obtain the Samsung ratingbar and set the Samsung ratingbar */
View getGuts (){
If (guts = null)
Guts = base. getChildAt (1 );
Return guts;
}

Void setGuts (View guts ){
This. guts = guts;
}
}

Go through the previous example and bind the listview to an adapter through setlistadapter in the program. It will call setadapter (listadapter adapter) in step 1 ), we use the ratenablewrapper class to implement the listadapter interface. This is the key to creating our own listview.

// Step 2: implement the ListAdapter Interface
Private class RatenableWrapperImplements ListAdapter{
//Step 2.1: Let's take a look at the parameters of setListAdapter (which also implement ListAdapter) and setAdapter (). We need to save this parameter.
// Context: Pass the displayed Activity, which is usually passed. Of course, you can also directly get it through getContext ().
// Rates []: record the number of stars for each Samsung RatingBar. For our example, Set
ListAdapter delegate =Null;
Context context = null;
Float [] rates = null;
//Step 2.2: Implement the constructor, record related parameters, and set 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 the ListAdapter interface, as shown below, directly use the passed parameter delegate, which is also the implementation class of ListAdapter. We will focus on getView (), and others will directly call delegate.
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: GetView
Public ViewGetview(Int position, View convertView, ViewGroup parent ){
ViewWrapper wrap = null;
// ViewWrapper is used to keep the widgets of each List element. We will give them later.
View row = convertView;
//Step 2.4.1: If you have not created a View for this List unit, create it. This View is divided into two parts: Samsung RatingBar on the left and View passed on the right.
If (convertView = null ){
//Step 2.4.1.1: Set the View to horizontal LinearLayout, followed by row = layout;
LinearLayout layout = new LinearLayout (context );
Layout. setOrientation (LinearLayout. HORIZONTAL );
// (1) The first part is the Samsung RatingBar, which sets related attributes,
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 the passed View, which sets the relevant attributes,
View guts =Delegate. getview(Position, null, parent);
Guts. setLayoutParams (new LinearLayout. LayoutParams (
LinearLayout. LayoutParams. WRAP_CONTENT, LinearLayout. LayoutParams. FILL_PARENT ));
// (3) place on LinearLayout
Layout. addView (rate );
Layout. addView (guts );

//Step 2.4.1.2: Set trigger processing for Samsung RaingBar. In this example, we only store the clicked stars in rates.
This requires that the widget RatingBar be bound with the Index, that is, the position, so we need to setTag the ratingbar.
RatingBar. OnRatingBarChangeListener l =
New RatingBar. OnRatingBarChangeListener (){
Public void onratingchanged (ratingbar, float rating, Boolean fromuser ){
Rates [(integer) ratingbar. gettag ()] = rating;
}
};
Rate. setonratingbarchangelistener (L );
//Step 2.4.1.3: Sets the UI element wrap of listview to implement bundling.
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 and set ratingbar to settag ()
Rate. settag (New INTEGER (position ));
Rate. setrating (rates [position]);
// Step 2.4.1.5, respond to step 2.4.1.1 and assign values to the row
Row = layout;

} Else {// Step 2.4.2:If you have created a View for this List unit. If we add Log. d. We will find that all the eight list elements on the first screen need to be created. However, if the scroll screen contains most of the list elements, the else branch is entered. It is unclear how Android handles the specific processing. It can intelligently process the list element UI based on the original situation. it is imagined that it intelligently processes the UI layout and generates corresponding widgets, however, from the perspective of the program, these widgets do not pass the Data assignment in the first step. Therefore, they involve non-UI parts and should be safely assigned a value on this branch. Note This.
Wrap = (ViewWrapper) convertView. getTag ();
//Step 2.4.2.1:A view is passed, and the view may be updated based on the scrolling screen. We also need to process it.
Wrap. setguts (delegate. getview (Position, wrap. getguts (), parent ));

//Step 2.4.2.2: Bind ratingbar and postiion (settag), and set the star level for raingbar based on the value stored in rates [].
Wrap. getratingbar (). settag (New INTEGER (position ));
Wrap. getratingbar (). setrating (rates [position]);
}

Return row;
}
}

Step 3: Experiment

Android Study Notes (17th): Change the listview of the XML file in the listview example to com. Wei. Android. Learning. ratingview, as shown in the figure below.

Question 1: If listitemclick is triggered

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

Getlistview (). setonitemclicklistener (New onitemclicklistener (){
Public void onitemclick (adapterview <?> Parent, view, int position, long ID ){
Toast. maketext (getapplicationcontext (), items [position], Toast. length_short). Show ();
}
});

We tried to click and found that the itemlist clicking operation could not be started. Itemlist is a layout with a widget and a passed view. Both widgets and views can be clicked and have a higher priority. To solve this problem, we add the following processing in getview:

Layout. setdescendantfocusability (viewgroup. focus_block_descendants );

Or describe each view in layout.

Guts. setfocusable (false );
Rate. setfocusable (false );

Because of the view settings, layout_width = wrap_content is used, we find that the blank space for clicking list item is valid, but clicking widgets is invalid, you can forcibly disable widgets from listening to click events for processing.

Guts. setclickable (false );

In this way, the entire View is a valid listening area for ListItemClick.

Question 2: How to handle internal widget triggers at the same time-Get Widgets

For example, in the main activity, setListAdapter (new ArrayAdapter <String> (this, android. R. layout. simple_list_item_checked, items); there is also checked in item. For a better UI experience, in getView, we set the property layout_width of guts to fill_parent. We hope that the Checked status of the Item will change when the ListItem is pressed.

In onItemClick (), the parameter View is actually a ListItem. In this example, it is the layout/row in getView. We can add a function in RatingView (ListView) to return the passed View (that is, the View on the right of layout), as shown below:

Public View getMyView (View v ){
ViewWrapper wrap = (ViewWrapper) v. getTag ();
Return wrap. getGuts ();
}

For android. R. layout. simple_list_item_checked, the type of this View is CheckedTextView. You can use setChecked () to set it. It seems that there is no problem, but we find that the click is not working, and the check status of other items will change inexplicably. Introduce the next discussion.

Question 3: What should I pay attention to when refreshing getView ()?

We added the trace log to getView () and found that when we click Item, the getView of the current screen will be refreshed. To ensure that the refresh will not change, like the Samsung ratingbar, you need to keep the check status of the item and reset it, just like ratingbar. For example, (CheckedTextView) wrap. getGuts (). setChecked (checks [position]); among them, checkes [] is used to save the check status. In this way, the entire display is normal. We need to refresh widgets with status changes in getView.

Wait, we need to modify our custom class. We only know what the passed View is to be added to the Samsung ratingbar. This deviates from our initial goal. We can perform type check getViewType on the passed View. If it is CheckedTextView, perform related operations.

In retrospect, the UI style of Android is not complicated, so we don't need to worry about it.

 

Related Links: My Andriod development articles

Related Article

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.