简体   繁体   中英

How can I create a Custom Android Listview header and group them into days

My goal is to create an application that display a list of data that are grouped by the days. Please refer to the below for actual screenshot.

我想要的应用程序的屏幕截图

In order to achieve this design, I have used custom arraylist adapter to make this design happen. Below is my class file for DiaryListAdapter

public class DiaryListAdapter extends ArrayAdapter<Records> {

/**
 * Adapter context
 */
Context mContext;

/**
 * Adapter View layout
 */
int mLayoutResourceId;

int selectedItem = -1;


private Records _records;

public DiaryListAdapter(Context context, int layoutResourceId, ArrayList<Records> recordItems) {
    super(context, layoutResourceId, recordItems);

    this.mContext = context;
    this.mLayoutResourceId = layoutResourceId;
}

private static class ViewHolder {
    TextView diaryTime, diarySysDia, diaryPul, itemDate, itemToday;
    LinearLayout llDiaryHead;
}



/**
 * Returns the view for a specific item on the list
 */
@Override
public View getView(int position, View convertView, ViewGroup parent) {


    // Declare the new object
    ViewHolder viewHolder;

    if (convertView == null) {



        LayoutInflater inflater = (LayoutInflater) mContext
                .getSystemService(Activity.LAYOUT_INFLATER_SERVICE);

        convertView = inflater.inflate(R.layout.lv_diarycontent_adapter, null);

        // Instantiate the object
        viewHolder = new ViewHolder();

        viewHolder.itemDate = (TextView) convertView.findViewById(R.id.itemDate);
        viewHolder.itemToday = (TextView) convertView.findViewById(R.id.itemToday);
        viewHolder.diaryTime = (TextView) convertView.findViewById(R.id.itemTime);
        viewHolder.diarySysDia = (TextView) convertView.findViewById(R.id.itemSysDia);
        viewHolder.diaryPul = (TextView) convertView.findViewById(R.id.itemPulse);
        viewHolder.llDiaryHead = (LinearLayout) convertView.findViewById(R.id.ll_diaryhead);


        convertView.setTag(R.id.TAG_DIARY_VIEWHOLDER_ID, viewHolder);

    } else {

        // Instantiate the new object
        viewHolder = (ViewHolder) convertView.getTag(R.id.TAG_DIARY_VIEWHOLDER_ID);

    }

    // Declare the reminder object
    _records = getItem(position);

    if (_records.getIsDateHead()) {

        // Hide the layout header
        viewHolder.llDiaryHead.setVisibility(View.VISIBLE);

        // Display the value on textview
        viewHolder.itemDate.setText(FormatterMgr.DSPLY_DATE_LSTVIEW.format(_records.getRecordCreatedOn()));

        // Display the value inside the content
        viewHolder.diaryTime.setText(_records.getRecordCreatedOn().toString());
        viewHolder.diarySysDia.setText(_records.getSys() + "/" + _records.getDia());
        viewHolder.diaryPul.setText(Float.toString(_records.getHr()));


    } else {

        // Hide the layout header
        viewHolder.llDiaryHead.setVisibility(View.GONE);

        // Display the value inside the content
        viewHolder.diaryTime.setText(_records.getRecordCreatedOn().toString());
        viewHolder.diarySysDia.setText(_records.getSys() + "/" + _records.getDia());
        viewHolder.diaryPul.setText(Float.toString(_records.getHr()));
    }




    convertView.setTag(R.id.TAG_DIARY_LIST_ID, _records);


    return convertView;
}

public void setSelectedItem(int selectedItem) {
    this.selectedItem = selectedItem;
}

Next class would be, DiaryFragment . This is the UI code behind file for me to program the listview to be displayed inside the page. This is the code where I have difficulty attempting to display the listview and grouped by the days accordingly.

public class DiaryFragment extends Fragment {
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String ARG_DIARY = "diary";
private static final String ARG_PARAM2 = "param2";

// TODO: Rename and change types of parameters
private String mParam1;
private String mParam2;


RecordsTableHelper rth;

HashSet<String> uniqueSet;
ArrayList<Records> mRecordsArrayList;
ListView mDiaryListView;


/**
 * Use this factory method to create a new instance of
 * this fragment using the provided parameters.
 *
 * @param param1 Parameter 1.
 * @param param2 Parameter 2.
 * @return A new instance of fragment DiaryFragment.
 */
// TODO: Rename and change types and number of parameters
public static DiaryFragment newInstance(String param1, String param2) {
    DiaryFragment fragment = new DiaryFragment();
    Bundle args = new Bundle();
    args.putString(ARG_DIARY, param1);
    args.putString(ARG_PARAM2, param2);
    fragment.setArguments(args);

    return fragment;
}

public DiaryFragment() {
    // Required empty public constructor
}

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    if (getArguments() != null) {
        mParam1 = getArguments().getString(ARG_DIARY);
        mParam2 = getArguments().getString(ARG_PARAM2);

    }
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fragment_diary, container, false);


    // Declare the database to retrieve all the data from the table
    DatabaseHelper _dbHelper = DBMgr.openConnection(getContext());
    rth = new RecordsTableHelper(_dbHelper.getDatabase());


    // Get all the records value and store inside an array list
    mRecordsArrayList = new ArrayList<Records>(rth.getAllRecords());
    Collections.sort(mRecordsArrayList, new RecordsComparator()); // Sort all the arraylist according to its date time


    //mRecordsArrayListSize = mRecordsArrayList.size();

    mDiaryListView = (ListView)view.findViewById(R.id.listViewDiary);
    mDiaryListView.setOnItemClickListener(new OnPlandetailsitemClickListener());

    setHasOptionsMenu(true);

    return view;
}





@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
    inflater.inflate(R.menu.menu_diary, menu);
    super.onCreateOptionsMenu(menu,inflater);
}


@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Handle action bar item clicks here. The action bar will
    // automatically handle clicks on the Home/Up button, so long
    // as you specify a parent activity in AndroidManifest.xml.
    int id = item.getItemId();

    //noinspection SimplifiableIfStatement
    if (id == R.id.action_adddiary) {
        Intent intent = new Intent(getActivity(), NewDiaryActivity.class);
        startActivityForResult(intent, ActivityResults.newdiaryactivityresult);

        // Create Animation
        getActivity().overridePendingTransition(R.anim.slide_in_right, R.anim.slide_out_left);
    }

    return super.onOptionsItemSelected(item);
}

@Override
public void onResume() {
    super.onResume();


    // Get the total day sum from the database
    int totalUniqueDays = getTotalUniqueDays();


    /* Declare the database to retrieve all the data from the table
    DatabaseHelper _dbHelper = DBMgr.openConnection(getContext());
    rth = new RecordsTableHelper(_dbHelper.getDatabase());
    */


    // 1) Create a for loop
    for (int i = 0; i<mRecordsArrayList.size(); i++) {




        Log.d("NON REPEATED DAYS", FormatterMgr.DB_DATE.format(mRecordsArrayList.get(i).getRecordCreatedOn()));

        // Set the first column header
        if (i==0) {
            // Add it into the arraylist
            mRecordsArrayList.get(i).setDateHead(true);

        }





        // 2) Inside the for loop, set the comparison of unique value occurs in the record array list method by checking the getUniqueDaysPos method
        // 3) If the unique value occurred, set the date head inside the arraylist
        // 4) Store the arraylist into the adapter

        /*
        // Get the total number of repeated days
        int totalRepeatedDays = getTotalRepeatedDays(mRecordsArrayList.get(i).getRecordCreatedOn());

        for (int j = 0; j<totalRepeatedDays; j++) {
            if (j==0) {
                // Add it into the arraylist
                mRecordsArrayList.get(j).setDateHead(true);
            }
        }
        */



    }


    DiaryListAdapter adapter = new DiaryListAdapter(getActivity(),
            R.layout.lv_diarycontent_adapter, mRecordsArrayList);
    mDiaryListView.setAdapter(adapter);


}

//response the click on listview
//the click listener for pastplan listview
private class OnPlandetailsitemClickListener implements ListView.OnItemClickListener {
    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {

        DiaryListAdapter adapter = (DiaryListAdapter) mDiaryListView.getAdapter();

        adapter.setSelectedItem(position);
        mDiaryListView.setAdapter(adapter);

        // Get the ID
        Records _records = (Records)view.getTag(R.id.TAG_DIARY_LIST_ID);


        //Direct to the reminder info activity
        Intent intent = new Intent(getActivity(), NewDiaryActivity.class);
        intent.putExtra(IntentResults.newDiary_id_val, _records.getRecord_id());

        startActivityForResult(intent, ActivityResults.inforeminderactivityresult);

        // Create Animation
        getActivity().overridePendingTransition(R.anim.slide_in_right, R.anim.slide_out_left);
    }
}




// Get the overall number of non repeated days inside record database
public int getTotalUniqueDays() {



    // Declare the current date and next date as 0
    String currentDate, nextDate = null;

    // Declare the result as 0. The result will be produce the outcome of the final result
    int result = 0;

    ArrayList<String> tempRecordsArrayList = new ArrayList<String>();

    // Declare the database to retrieve all the data from the table
    for (int i = 0; i<mRecordsArrayList.size(); i++) {

        // Convert the date time to date
        currentDate = FormatterMgr.DB_DATE.format(mRecordsArrayList.get(i).getRecordCreatedOn());

        tempRecordsArrayList.add(currentDate);


    }
    uniqueSet = new HashSet<String>();
    uniqueSet.addAll(tempRecordsArrayList);
    return uniqueSet.size();
}


public ArrayList<Integer> getUniqueDaysPos() {

    // 1) Get the unique set and store into arraylist
    ArrayList<String> tempUniqueSet = new ArrayList<String>(uniqueSet);

    // 2) Get the full set of record array list
    ArrayList<Records> tempRecordsSet = mRecordsArrayList;

    // 3) Create the object of null arraylist integer
    ArrayList<Integer> uniqueDaysPos = new ArrayList<Integer>();

    // 4) Loop through the fullset arraylist and produce the result of the position of unique dates inside the full set of array list
    for (int i = 0; i<tempRecordsSet.size(); i++) {

        // 5) Store the unique dates position inside the set of integer arraylist
        uniqueDaysPos.add(tempRecordsSet.indexOf(tempUniqueSet));
    }


    return uniqueDaysPos;
}

public int getTotalRepeatedDays(Date dateValue) {

    // Declare the database to retrieve all the data from the table
    DatabaseHelper _dbHelper = DBMgr.openConnection(getContext());
    rth = new RecordsTableHelper(_dbHelper.getDatabase());

    // Get all the records value and store inside an array list
    ArrayList<Records> mRecordsDateRepeatedList = rth.getAllRecordsByDate(dateValue);


    return mRecordsDateRepeatedList.size();

}


 }

Below is the lv_diarycontent_adapter XML file for the list adapter. In this case, the code behind of DiaryListAdapter will toggle the header based on the condition of each record.

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

<!-- START OF HEAD LAYOUT -->
<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:paddingLeft="15dp"
    android:paddingTop="5dp"
    android:paddingBottom="5dp"
    android:orientation="horizontal"
    android:id="@+id/ll_diaryhead"
    android:background="@color/colorPrimary">


    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="0.3">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Mon 1, 1976"
            android:id="@+id/itemDate"
            android:layout_alignParentLeft="true"
            android:textAppearance="?android:attr/textAppearanceListItemSmall"
            android:textStyle="bold"
            android:textColor="@color/font_color_white"
            android:layout_marginBottom="5dp" />





    </LinearLayout>


    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="0.7">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text=""
            android:id="@+id/itemToday"
            android:textAppearance="?android:attr/textAppearanceListItemSmall"
            android:textStyle="bold"
            android:textColor="@color/font_color_white" />

    </LinearLayout>

</LinearLayout>
<!-- END OF HEAD LAYOUT -->


<!-- START OF BODY LAYOUT -->
<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal">



    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="0.25"
        android:gravity="center_horizontal">

       <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="10:30"
            android:id="@+id/itemTime"
            android:textAppearance="?android:attr/textAppearanceListItemSmall"
            android:layout_marginBottom="5dp" />





    </LinearLayout>


    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="0.5"
        android:gravity="center_horizontal">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="120/75"
            android:id="@+id/itemSysDia"
            android:textAppearance="?android:attr/textAppearanceListItemSmall"
            ></TextView>

    </LinearLayout>

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="0.25"
        android:gravity="center_horizontal">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="80"
            android:id="@+id/itemPulse"
            android:textAppearance="?android:attr/textAppearanceListItemSmall"
            ></TextView>

    </LinearLayout>

</LinearLayout>
<!-- END OF BODY LAYOUT -->

I am now stuck to create the listview and grouped the records into date. My attempts so far, is to sort the records by date in ascending order, and populate the listview with the data. I have tried using nested for loop with the number of unique days and loop the duplicate days inside. But, it doesn't work.

Thank you for your time reading this, and will be glad to answer all your question if you have any doubts!

You can try..& android will look like bellow 在此处输入图片说明

  1. Create a project
  2. copy & paste to activity_main.xml

      <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <!-- Content Here --> <LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight=".1" android:background="#f1e7ce" android:orientation="vertical"> <ListView android:id="@+id/listview" android:layout_width="match_parent" android:layout_height="wrap_content"/> </LinearLayout> </LinearLayout> 
  3. create section_header.xml & paste bellow code

      <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <TextView android:id="@+id/section_header" android:layout_width="match_parent" android:layout_height="30dp" android:background="#ff0092f4" android:textColor="#FFFFFF" android:text="Header" android:textSize="17sp" android:padding="4dp" /> </LinearLayout> 
  4. Create row_item.xml & paste bellow code

      <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="horizontal" > <TextView android:id="@+id/time_time" android:layout_width="0dp" android:layout_height="70dp" android:layout_weight="1" android:textSize="20sp" android:text="12.00 PM" android:layout_marginLeft="15dp" android:gravity="center_vertical" android:textColor="#cc222222"/> <TextView android:id="@+id/tv_item_sysdia" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:textSize="15sp" android:text="120/75" android:textColor="#cc222222" android:layout_marginRight="10dp" android:gravity="center_vertical|center"/> <TextView android:id="@+id/tv_item_plus" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:textSize="15sp" android:text="80" android:textColor="#cc222222" android:layout_marginRight="10dp" android:gravity="center_vertical|center"/> </LinearLayout> 
  5. Create Class ItemModel & paste bellow code

      public class ItemModel implements Comparable<ItemModel>{ private boolean isSectionHeader; private String itemTime; private String itemSysDia; private String itemPulse; private String date; public ItemModel(String itemTime, String itemSysDia, String itemPulse, String date) { this.itemTime = itemTime; this.itemSysDia = itemSysDia; this.itemPulse = itemPulse; this.date =date; isSectionHeader = false; } public String getItemTime() { return itemTime; } public void setItemTime(String itemTime) { this.itemTime = itemTime; } public String getItemSysDia() { return itemSysDia; } public void setItemSysDia(String itemSysDia) { this.itemSysDia = itemSysDia; } public String getItemPulse() { return itemPulse; } public void setItemPulse(String itemPulse) { this.itemPulse = itemPulse; } public String getDate() { return date; } public void setDate(String date) { this.date = date; } public boolean isSectionHeader() { return isSectionHeader; } @Override public int compareTo(ItemModel itemModel) { return this.date.compareTo(itemModel.date); } public void setToSectionHeader() { isSectionHeader = true; } } 
  6. In MainActivity Paste bellow code

      public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ArrayList<ItemModel> itemsList = new ArrayList<>(); ListView list = (ListView) findViewById(R.id.listview); itemsList = sortAndAddSections(getItems()); ListAdapter adapter = new ListAdapter(this, itemsList); list.setAdapter(adapter); } private ArrayList sortAndAddSections(ArrayList<ItemModel> itemList) { ArrayList<ItemModel> tempList = new ArrayList<>(); //First we sort the array Collections.sort(itemList); //Loops thorugh the list and add a section before each sectioncell start String header = ""; for(int i = 0; i < itemList.size(); i++) { //If it is the start of a new section we create a new listcell and add it to our array if(!(header.equals(itemList.get(i).getDate()))) { ItemModel sectionCell = new ItemModel(null, null,null,itemList.get(i).getDate()); sectionCell.setToSectionHeader(); tempList.add(sectionCell); header = itemList.get(i).getDate(); } tempList.add(itemList.get(i)); } return tempList; } public class ListAdapter extends ArrayAdapter { LayoutInflater inflater; public ListAdapter(Context context, ArrayList items) { super(context, 0, items); inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); } @Override public View getView(int position, View convertView, ViewGroup parent) { View v = convertView; ItemModel cell = (ItemModel) getItem(position); //If the cell is a section header we inflate the header layout if(cell.isSectionHeader()) { v = inflater.inflate(R.layout.section_header, null); v.setClickable(false); TextView header = (TextView) v.findViewById(R.id.section_header); header.setText(cell.getDate()); } else { v = inflater.inflate(R.layout.row_item, null); TextView time_time = (TextView) v.findViewById(R.id.time_time); TextView tv_item_sysdia = (TextView) v.findViewById(R.id.tv_item_sysdia); TextView tv_item_plus = (TextView) v.findViewById(R.id.tv_item_plus); time_time.setText(cell.getItemTime()); tv_item_sysdia.setText(cell.getItemSysDia()); tv_item_plus.setText(cell.getItemPulse()); } return v; } } private ArrayList<ItemModel> getItems(){ ArrayList<ItemModel> items = new ArrayList<>(); items.add(new ItemModel("10.30", "120/10","80","Tue,31 Oct 17")); items.add(new ItemModel("10.30", "142/95","95","Tue,31 Oct 17")); items.add(new ItemModel("15.30", "120/95","200","Tue,31 Oct 17")); items.add(new ItemModel("20.30", "120/10","80","Tue,29 Oct 17")); items.add(new ItemModel("10.30", "120/10","50","Tue,29 Oct 17")); items.add(new ItemModel("10.30", "140/10","80","Tue,28 Oct 17")); items.add(new ItemModel("10.30", "30/75","40","Tue,28 Oct 17")); items.add(new ItemModel("10.30", "150/80","70","Tue,28 Oct 17")); return items; } } 
  7. You can download the project from GitHub: https://github.com/enamul95/CustomHeaderWith

  8. You can see the tutorials Links: http://www.iyildirim.com/tech-blog/creating-listview-with-sections

I think your problem is to achieve different type item layout in ListView. And it would more easy to achieve use BaseAdapter instead of ArrayAdapter. Wish this link would help you :)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM