Minelava
Minelava

Reputation: 221

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.

Screenshot of the app that I want to have

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!

Upvotes: 1

Views: 5228

Answers (2)

Enamul Haque
Enamul Haque

Reputation: 5053

You can try..& android will look like bellow enter image description here

  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

Upvotes: 2

TellH
TellH

Reputation: 1

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 :)

Upvotes: 0

Related Questions