יום ראשון, פברואר 13

Expandable List חלק שני

זהו המשך לפוסט הקודם בנושא.  תוצג כאן דוגמא המתבססת על הדוגמא שהוצגה בפוסט הקודם, עם מספר שיפורים:
  • ביטול קלט הנתונים מתוך מערך ב-java. 
  • קליטת הנתונים מתבצעת בשתי דרכים:
    • בהתחלה, ב-onCreate,  קריאת נתונים מתוך קובץ = raw data.
    • בהמשך ניתן להוסיף רשומות אינטראקטיבית, תוך שימוש במסך מיוחד לקליטת הנתונים. 
  • תוספת onChildClick listener. 
השיפורים שהוכנסו לא קשורים ישירות לנושא ה-ExapndableList, והן רק משלבות "שיכלולים" נוספים כמו אפשרויות נוספות לקליטת נתונים מקובץ (BufferedReader) והכנסת נתונים אינטראקטיבית לתוך ה-Lists.

נתחיל עם תצונות המסכים.
המסך הראשון: המסך שנוצר אחרי onCreate. זהה כמעט לזה שבפוסט הקודם. נוסף כפתור להוספת פריט לרשימה.





המסך השני, מסך להוספת פריט לרשימה:






המסך הנ"ל כולל הכנסת שדות לתוך EditView. שם העיר נבחר עם Spinner.
הנתונים ימשיכו להיות מסודרים בקבוצות לפי שם העיר.


נסתכל על הקבצים.
קובץ ה-layout של המסך הראשי דומה לזה שבפוסט הקודם. נווסף רק הכפתור. הנה תוכנו:


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
   
             <Button   
                 android:id="@+id/add_entry"
                android:layout_width="match_parent"                
                android:layout_height="wrap_content"
                android:layout_marginLeft="20px"
                android:text="@string/button_add_entry"
    />

<TextView 
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:textSize="18sp"
    android:gravity="center"
    android:textStyle="bold"
    android:text="@string/address_book_title"
    />
       <ExpandableListView android:id="@+id/android:list"
               android:layout_width="fill_parent"
               android:layout_height="fill_parent"/>

   
</LinearLayout>


קובץ ה-layout של האיבר ברשימת ה-child לא השתנה. אציג אותו שוב בכל זאת:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content">

    <TextView android:id="@+id/textview_name"
         android:paddingLeft="5px"
         android:textSize="15px"
         android:layout_width="120px"
         android:layout_height="wrap_content"/>

    <TextView android:id="@+id/textview_address"
         android:textSize="10px"
         android:layout_width="120px"
         android:layout_height="wrap_content"/>
        
    <TextView android:id="@+id/textview_tel"
         android:textSize="10px"
         android:layout_width="120px"
         android:layout_height="wrap_content"/>

</LinearLayout>



הנה קובץ ה-layout של המסך השני - המסך להוספת פריט. שם הקובץ:activity2.xml


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >
   

    
 
         <TextView   
                 android:id="@+id/top_title"
                android:layout_width="match_parent"                
                android:layout_height="wrap_content"
                android:layout_marginLeft="20px"
                android:text="@string/top_title"
    />
   
       <TextView   
                 android:id="@+id/textview_city_spinner_title"
                android:layout_width="match_parent"                
                android:layout_height="wrap_content"
                android:layout_marginLeft="20px"
                android:text="@string/city_spinner_title"
    />
 
   
      <Spinner    android:id="@+id/city_spinner"
                android:layout_width="match_parent"                
                android:layout_height="wrap_content"
                android:layout_marginLeft="20px"
               
    />
   
   
     <TextView   
                 android:id="@+id/textview_name_title"
                android:layout_width="match_parent"                
                android:layout_height="wrap_content"
                android:layout_marginLeft="20px"
                android:text="@string/textview_name_title"
    />
   
         <EditText   
                 android:id="@+id/edit_text_name"
                android:layout_width="match_parent"                
                android:layout_height="wrap_content"
                android:layout_marginLeft="20px"
    />

        <TextView
         android:id="@+id/textview_address_title"
         android:padding="10dip"
         android:textSize="18sp"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:text="@string/textview_address_title"
          />

            <EditText   
                 android:id="@+id/edit_text_address"
                android:layout_width="match_parent"                
                android:layout_height="wrap_content"
                android:layout_marginLeft="20px"
    />
          <TextView   
                 android:id="@+id/textview_tel_number"
                android:layout_width="match_parent"                
                android:layout_height="wrap_content"
                android:layout_marginLeft="20px"
                android:text="@string/textview_tel_title"
    />

          <EditText   
                 android:id="@+id/edit_text_tel_number"
                android:layout_width="match_parent"                
                android:layout_height="wrap_content"
                android:layout_marginLeft="20px"
    />
     <Button
     android:id="@+id/button_commit"
     android:text="@string/button_commit_entry"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:layout_gravity="center">
     </Button>
    
</LinearLayout>


ישנם עוד שני קבצים שאציג לפני שנעבור לג'אוות:
  1. הקובץ שמכיל את רשימת הכתובות הראשונית.
  2. רשימת הערים עבור ה-spinner.
הנה קובץ רשימת הכתובות הראשונית. שם קובץ: phonebook.txt והוא יושב ב/layout/raw.
Tel Aviv, David Levi, Nordau 8,052-2323232
Haifa, Yosi Das,Lilinblum 33,03-2323244
Tel Aviv, Rami Kook,Gordon 12,03-2323221
Tel Aviv, Sami Nof,Gordon 12,03-2323221
Haifa, David Levi, Nordau 8,052-2323232
Jerusalem,Yosi Das,Lilinblum 33,03-2323244
Tel Aviv,Dafi Cin,Gordon 12,03-2323221
Haifa, Iris Hadad, Has 8,052-2323432
Tel Aviv,Rafi Masmus,Jabotinski 313,03-2323244
Jerusalem,Jako Bilbo,Sokolov 32,02-2323221
Haifa,  Itzik Solo,Sokolov 32,03-2324221
Tel Aviv,Nahum Fantog,King George 32,03-2324221
Tel Aviv,Irit Singer,King David 32,03-2388221
כל רשומה נמצאת בשורה נפרדת, והשדות מופרדים עם ",". 


רשימת הערים עבור ה-spinner. נמצא ב: values/arrays.xml


<?xml version="1.0" encoding="utf-8"?>
        <resources>
            <array name="cities">            
            <item>Afula</item>            
            <item>Bat-Yam</item>            
            <item>CarCoor</item>            
            <item>Dimona</item>
            <item>Eilta</item>
            <item>Fasuta</item>            
            <item>Ganei Tikva</item>            
            <item>Haifa</item>            
            <item>Izrael</item>
            <item>Jerusalem</item>
            <item>Kiriat Shmona</item>
            <item>Liman</item>
            <item>Metula</item>
            <item>Naharia</item>
            <item>Ofakim</item>
             <item>Petah=Tikva</item>
            <item>Qualkilia</item>
            <item>Ramat Gan</item>
            <item>Shfayim</item>
            <item>Tel Aviv</item>
          </array>  
  </resources>


הנה הגאוות. קודם כל הקובץ הראשי. לא ארחיב ואחזור על ההברים שניתנו בפוסט הקודם.

ה-class הראשי:



import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import android.app.ExpandableListActivity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ExpandableListAdapter;
import android.widget.ExpandableListView;
import android.widget.SimpleExpandableListAdapter;
import android.widget.Toast;
public class MyExapandablePart2 extends ExpandableListActivity {
    private static final int CREATE_LIST_ENTRY = 1;

    private static final String CITY = "CITY";
    private static final String NAME = "NAME";
    private static final String ADDRESS = "ADDRESS";
    private static final String TEL = "TEL";
    private ExpandableListAdapter adapter;
    ArrayList<Map<String, String>> groupData = new ArrayList<Map<String, String>>();
    ArrayList<String> cityList = new ArrayList<String>();
    ArrayList<List<Map<String, String>>> childrenData = new ArrayList<List<Map<String, String>>>();
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        buildListsFromFile();
        adapter = new SimpleExpandableListAdapter(
                this,
                groupData,
                android.R.layout.simple_expandable_list_item_1,
                new String[] { CITY },
                new int[] { android.R.id.text1 },
                childrenData,
                R.layout.child_list_entry,
                new String[] { NAME, ADDRESS, TEL },
                new int[] { R.id.textview_name, R.id.textview_address, R.id.textview_tel }
        );
        setListAdapter(adapter);
        Button buttonAddEntry = (Button)findViewById(R.id.add_entry);
        buttonAddEntry.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                Intent intent = new Intent(MyExapandablePart2.this, EntryAddActivity.class);
                startActivityForResult(intent,CREATE_LIST_ENTRY );
                }
            });
    }
    private void buildListsFromFile(){
        InputStream inputStream = this.getResources().openRawResource(R.raw.phonebook);
             BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
             try{
                 String line = "";
                 while ((line = bufferedReader.readLine()) != null) {
                String[] strings = line.split(",");
                String city = strings[0].trim();
                String name = strings[1].trim();
                String address = strings[2].trim();
                String tel = strings[3].trim();
                buildListsEntry(city, name, address, tel);
                Log.d("ronen post buildListsEntry",""+city);
                 }
             }catch(Exception e){
// get class name:
                 Log.e(getClass().getSimpleName(), "readInputFile problem");
        }
    }
    Map<String, String> groupMap = new HashMap<String, String>();
    private void buildListsEntry(String city, String name, String address, String tel){
        if(-1 == cityList.indexOf(city)){
            groupMap = new HashMap<String, String>();
            groupData.add(groupMap);
            groupMap.put(CITY, city);
            cityList.add(city);
            ArrayList<Map<String, String>> child = new ArrayList<Map<String, String>>();
            childrenData.add(child);
        }
        List<Map<String, String>>  childCurr =childrenData.get(cityList.indexOf(city));
        Map<String, String> childMap = new HashMap<String, String>();
        childCurr.add(childMap);
        childMap.put(NAME, name);
        childMap.put(ADDRESS, address );
        childMap.put(TEL, tel );
    }
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == CREATE_LIST_ENTRY) {
            if (resultCode == RESULT_OK) {
                String  city    = data.getStringExtra("city");   
                String name    = data.getStringExtra("name");
                String address    = data.getStringExtra("address");
                String tel    = data.getStringExtra("tel");
                   buildListsEntry(city, name, address, tel);
            }
        }
    }
    @Override
    public boolean onChildClick(ExpandableListView parent, View v, int groupPosition,
            int childPosition, long id) {
            Toast.makeText(this,"Selected item: groupPosition = "+groupPosition+"\nChild Positin = "+childPosition+"\nid= "+id,Toast.LENGTH_LONG).show();
            return true;
    }
}


ה-class (כמובן extends ExpandableListActivity) כולל את המתודות הבאות:

  1. onCreate
  2. buildListsFromFile
  3. buildListsEntry
  4. onActivityResult
  5. onChildClick
הנה ה-class השני, שמופעל ע"י intent ב-onClick callback של הכפתור.


import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Spinner;

public class EntryAddActivity extends Activity {
        EditText editTextName;
        EditText editTextaddress;
        EditText editTexttel;
        Spinner spinnerCity;
   @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity2);
        spinnerCity = (Spinner) findViewById(R.id.city_spinner);
        editTextName = (EditText) findViewById(R.id.edit_text_name);
        editTextaddress = (EditText)findViewById(R.id.edit_text_address);
        editTexttel = (EditText)findViewById(R.id.edit_text_tel_number);
        Button buttonCommit = (Button)findViewById(R.id.button_commit);
        MyClickInterface buttonListener = new MyClickInterface();
        buttonCommit.setOnClickListener(buttonListener);
        ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, getResources()
                .getStringArray(R.array.cities));
        spinnerCity.setAdapter(adapter);
    }
    public class MyClickInterface implements View.OnClickListener{
        @Override
        public void onClick(View v){
            String myName = editTextName.getText().toString();
            String myAddress =  editTextaddress.getText().toString();
            String myTel =  editTexttel.getText().toString();
            String  myCity = spinnerCity.getSelectedItem().toString();
            Intent intent = new Intent();
            intent.putExtra("city", myCity);
            intent.putExtra("name", myName );
            intent.putExtra("address", myAddress);
            intent.putExtra("tel", myTel);
            setResult(RESULT_OK,intent);
            finish();
         }
    }
}

ב-onClick של כפתור ה-Commit מעבירים את הנתונים שהוכנסו דרך ה-EditViews וה-spinner לשדה ה-extra של ה-Intent, והם "משוגרים" חזרה ל-class השני, שם יטופלו ע"י המתודה onActivityResult - ה-callback שמטפל בהודעת ה-Intent החוזר.

הפעם לא ארחיב בהסברים מעבר לזה. אין כאן מרכיבים "חדשים".






2 תגובות:

  1. תודה על הפרסום , אבל אתה יכול להוסיף גם את האלמנט של המיון לפי שמות ?

    השבמחק
  2. אני משתמש באנדרואיד סטודיו , ושם אין את התיקייה raw איך אני בכל זאת יכול להעביר לו את המידע

    השבמחק