0

I create app for sports site and need to make calendar events. There is a detail which I can't understand: how to make headers within Recyclerview for display of tournaments name that not to specified near each game (example "Примера" on the screen).

enter image description here

Is there a library or anyways for my task? I don’t want create many static Recyclerview and find agile ways.

Of course, there are a lot of tournaments in the calendar, so the headers should be the same.

Main class of the calendar:

public class FootballResults extends Fragment implements 
View.OnClickListener, DatePickerDialog.OnDateSetListener{

private LinearLayoutManager linLM;
private FootballResultsAdapter adapter;
private ArrayList<FootballResultsData> dl;

String today_day;
String today_month;
String today_year;
String mDay;
String mMonth;
String mYear;

Button arrow_left;
Button arrow_right;
Button datepicker;

Switch swLive;

int n = 0;
//int n_plus = 1;

@SuppressLint("SetTextI18n")
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    View rv = inflater.inflate(R.layout.results_football, container, false);

    RecyclerView footballresults_feed1 = (RecyclerView) rv.findViewById(R.id.rcMatch1);

    dl = new ArrayList<>();

    footballresults_feed1.setLayoutManager(new LinearLayoutManager(getActivity()));
    adapter = new FootballResultsAdapter(getActivity(), dl);
    footballresults_feed1.setAdapter(adapter);

    arrow_left = (Button)rv.findViewById(R.id.arrow_left);
    arrow_right = (Button)rv.findViewById(R.id.arrow_right);
    datepicker = (Button)rv.findViewById(R.id.btnDatepick);
    swLive = (Switch)rv.findViewById(R.id.swLive);

    arrow_left.setOnClickListener(this);
    arrow_right.setOnClickListener(this);

    datepicker.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            datepickermethod ();
        }
    });

    swLive.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
        @Override
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
            if (isChecked) {swLive.setText("");}
            else {swLive.setText("");}
        }
    });

    currenttime();
    datepicker.setText(Integer.parseInt(mDay)+" "+TimeFormat.monthDef(Integer.parseInt(mMonth))+" "+mYear);

    ResultDisplay();

    return rv;
}

private void ResultDisplay() {
    @SuppressLint("StaticFieldLeak") AsyncTask<Integer, Void, Void> task = new AsyncTask<Integer, Void, Void>() {
        @Override
        protected Void doInBackground(Integer... integers) {

            ResultFeed ();

            return null;
        }

        @Override
        protected void onPostExecute(Void aVoid) {

            adapter.notifyDataSetChanged();
        }
    };
    task.execute();
}

void ResultFeed (){
    OkHttpClient client = new OkHttpClient();
    okhttp3.Request request = new okhttp3.Request.Builder()
            .url(C.RESULT_API+mYear+"/"+mMonth+"/"+mDay+"?sport_id=1")
            .build();
    try {
        okhttp3.Response response = client.newCall(request).execute();
        JSONObject object = new JSONObject(response.body().string());

        dl.clear();
        JSONArray sports = object.getJSONArray("sports");
        JSONObject tournament0 = sports.getJSONObject(0);

        JSONArray tournament = tournament0.getJSONArray("tournaments");
        for (int i=0; i<tournament.length(); i++){
            JSONObject matches1 = tournament.getJSONObject(i);
            Log.i (C.T, "Турнир: "+matches1.getString("tournament_name"));
            JSONArray matches0 = matches1.getJSONArray("matches");
            for (int j=0; j<matches0.length(); j++) {
                JSONObject matches = matches0.getJSONObject(j);

                String match_time = TimeFormat.TimeRadar(matches.getString("date_of_match")); //время начала матча
                String match_res = matches.getString("ft_value"); 
                String match_status = matches.getString("status");

                if (match_res.equals("null")) {match_res = "-:-";}
                if (match_status.equals("Не начался")) {match_status = "";}
                if (match_status.equals("null")) {match_status = "";}

                JSONObject team_home1 = matches.getJSONObject("team_home");
                String team_home = team_home1.getString("short_name");
                String team_home_logo = team_home1.getString("logo_small"); 

                JSONObject team_away1 = matches.getJSONObject("team_away");
                String team_away = team_away1.getString("short_name"); 
                String team_away_logo = team_away1.getString("logo_small"); 

                FootballResultsData data = new FootballResultsData(matches1.getString("tournament_name"),
                        match_time,
                        match_res,
                        team_home, team_away,
                        match_status,
                        team_home_logo,
                        team_away_logo);
            dl.add(data);
        }}

    } catch (IOException e) {
        e.printStackTrace();
    } catch (JSONException e) {
        e.printStackTrace();
    } catch (ParseException e) {
        e.printStackTrace();
    }
}

@SuppressLint("SimpleDateFormat")
void currenttime () {
    long date_today = System.currentTimeMillis();
    today_day = new SimpleDateFormat("dd").format(date_today);
    today_month = new SimpleDateFormat("MM").format(date_today);
    today_year = new SimpleDateFormat("yyyy").format(date_today);
    mDay = today_day; mMonth = today_month; mYear = today_year;
}

@SuppressLint("SimpleDateFormat")
void calendar (String dd, String mm, String yyyy, int day_n) {
    String sourceDate = yyyy+"-"+mm+"-"+dd;
    SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
    Date myDate;
    try {
        myDate = format.parse(sourceDate);
        myDate = DateUtil.addDays(myDate, day_n);
        String mDate = new SimpleDateFormat("dd MM yyyy").format(new SimpleDateFormat("EEE MMM dd kk:mm:ss zzzz yyyy").parse(myDate.toString()));
        mDay = new SimpleDateFormat("dd").format(new SimpleDateFormat("dd MM yyyy").parse(mDate));
        mMonth = new SimpleDateFormat("MM").format(new SimpleDateFormat("dd MM yyyy").parse(mDate));
        mYear = new SimpleDateFormat("yyyy").format(new SimpleDateFormat("dd MM yyyy").parse(mDate));
        Log.i(C.T, mDate);
    } catch (ParseException e) {
        e.printStackTrace();
    }
}

@SuppressLint("SetTextI18n")
@Override
public void onClick(View v) {
    //currenttime ();
    switch (v.getId()) {
        case R.id.arrow_left: {n=n-1; break;}
        case R.id.arrow_right: {n=n+1; break;}
        default: break;
    }
    calendar(today_day, today_month, today_year, n);
    datepicker.setText(Integer.parseInt(mDay)+" "+TimeFormat.monthDef(Integer.parseInt(mMonth))+" "+mYear);
    ResultDisplay();
}

@Override
public void onDateSet(DatePicker view, int year, int month, int dayOfMonth) {

}

void datepickermethod () {
    DatePickerDialog datepick = new DatePickerDialog(getContext(), new DatePickerDialog.OnDateSetListener() {
    @SuppressLint("SetTextI18n")
    @Override
    public void onDateSet(DatePicker view, int year, int month, int dayOfMonth) {
        datepicker.setText(dayOfMonth+" "+TimeFormat.monthDef(month+1)+" "+year);
        mDay = String.valueOf(dayOfMonth); mMonth = String.valueOf(month+1); mYear = String.valueOf(year);
        n=0;
        today_day = String.valueOf(dayOfMonth); today_month = String.valueOf(month+1); today_year = String.valueOf(year);
        ResultDisplay();
    }
        }, Integer.parseInt(today_year), Integer.parseInt(today_month)-1, Integer.parseInt(today_day));
    datepick.show();
}
}

For setters and getters:

class FootballResultsData {

public FootballResultsData(String tournament_name, String match_time, String match_result, String team_home, String team_away, String match_status, String team_home_logo, String team_away_logo) {
    this.setTournament_name(tournament_name);
    this.setMatch_time(match_time);
    this.setMatch_result(match_result);
    this.setTeam_home(team_home);
    this.setTeam_away(team_away);
    this.setMatch_status(match_status);
    this.setTeam_home_logo(team_home_logo);
    this.setTeam_away_logo(team_away_logo);
}

private String tournament_name;
private String match_time;
private String match_result;
private String team_home;
private String team_away;
private String match_status;
private String team_home_logo;
private String team_away_logo;

public String getMatch_time() { return match_time; }

public void setMatch_time(String match_time) {
    this.match_time = match_time;
}

public String getTeam_home() {
    return team_home;
}

public void setTeam_home(String team_home) {
    this.team_home = team_home;
}

public String getTeam_away() {
    return team_away;
}

public void setTeam_away(String team_away) {
    this.team_away = team_away;
}

public String getMatch_status() {
    return match_status;
}

public void setMatch_status(String match_status) {
    this.match_status = match_status;
}

public String getMatch_result() { return match_result; }

public void setMatch_result(String match_result) { this.match_result = match_result; }

public String getTeam_home_logo() {
    return team_home_logo;
}

public void setTeam_home_logo(String team_home_logo) {
    this.team_home_logo = team_home_logo;
}

public String getTeam_away_logo() {
    return team_away_logo;
}

public void setTeam_away_logo(String team_away_logo) {
    this.team_away_logo = team_away_logo;
}

public String getTournament_name() {
    return tournament_name;
}

public void setTournament_name(String tournament_name) {
    this.tournament_name = tournament_name;
}
}

Cardview for a display of match:

<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/tournament_result"    >

<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingStart="10dp"
    android:paddingEnd="10dp"
    android:background="@drawable/newsbody_file">

    <TextView
        android:id="@+id/linebelownews"
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:background="@color/colorNewsPressed" />

    <TextView
        android:id="@+id/match_time"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/linebelownews"
        android:text="22:00" />

    <TextView
        android:id="@+id/match_status"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentEnd="true"
        android:layout_alignParentTop="true"
        android:text="ост." />

    <TextView
        android:id="@+id/match_res"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_below="@id/match_time"
        android:layout_marginStart="8dp"
        android:layout_marginEnd="8dp"
        android:text="2:2"
        android:textStyle="bold" />

    <TextView
        android:id="@+id/match_th"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/match_time"
        android:layout_marginEnd="5dp"
        android:layout_toStartOf="@+id/logo_th"
        android:text="Динамо"
        android:textAlignment="viewEnd"
        android:textColor="#000000" />

    <TextView
        android:id="@+id/match_ta"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="5dp"
        android:layout_toEndOf="@+id/logo_ta"
        android:layout_below="@id/match_time"
        android:textColor="#000000"
        android:text="Шахтер" />

    <ImageView
        android:id="@+id/logo_th"
        android:layout_width="20dp"
        android:layout_height="20dp"
        android:layout_toStartOf="@id/match_res"
        android:layout_below="@+id/match_time"
        android:contentDescription="logo_th"
        app:srcCompat="@drawable/author_file" />

    <ImageView
        android:id="@+id/logo_ta"
        android:layout_width="20dp"
        android:layout_height="20dp"
        android:layout_below="@id/match_time"
        app:srcCompat="@drawable/author_file"
        android:layout_toEndOf="@id/match_res"
        android:layout_marginBottom="5dp"
        android:contentDescription="logo_th" />

    <TextView
        android:id="@+id/tournament_n"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBottom="@+id/match_status"
        android:layout_centerHorizontal="true"
        android:text="@string/name_tournament" />
</RelativeLayout>
</android.support.v7.widget.CardView>

And main layout with Recyclerview:

<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/tournament_result">

<android.support.v7.widget.RecyclerView
 android:id="@+id/rcMatch1"
 android:layout_width="match_parent"
 android:layout_height="wrap_content" />


<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:id="@+id/lCalendar">
    <Button
        android:id="@+id/arrow_left"
        android:layout_width="40dp"
        android:layout_height="40dp"
        android:layout_marginTop="5dp"
        android:layout_toStartOf="@+id/btnDatepick"
        android:background="@drawable/ic_arrow_left" />
    <Button
        android:id="@+id/arrow_right"
        android:layout_width="40dp"
        android:layout_height="40dp"
        android:layout_marginTop="5dp"
        android:layout_marginBottom="5dp"
        android:layout_toEndOf="@+id/btnDatepick"
        android:background="@drawable/ic_arrow_right" />
    <Button
        android:id="@+id/btnDatepick"
        android:layout_width="wrap_content"
        android:layout_height="40dp"
        android:layout_marginTop="5dp"
        android:layout_marginBottom="5dp"
        android:paddingStart="8dp"
        android:paddingEnd="8dp"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true" />
    <Switch
        android:id="@+id/swLive"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentStart="true"
        android:layout_centerVertical="true"
        android:layout_marginStart="16dp" />
</RelativeLayout>

</RelativeLayout> 

EDIT

Adapter:

class FootballResultsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private Context context;
private ArrayList<FootballResultsData> footballresults_data = new ArrayList<FootballResultsData>();

private static int View_Header = 0;
private static int View_Item = 1;

public FootballResultsAdapter(Context context, ArrayList<FootballResultsData> footballresults_data) {
    this.context = context;
    this.footballresults_data = footballresults_data;
}

@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

    RecyclerView.ViewHolder holder = null;
    if(viewType == View_Item) {
        View view = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.card_match, parent, false);
        holder = new ViewHolder_item(view);
    }
    else if(viewType == View_Header) {
        View view = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.card_tournament, parent, false);
        holder = new ViewHolder_header(view);
    }
    return holder;
}

@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {

    FootballResultsData NFD = footballresults_data.get(position);
    if (holder instanceof ViewHolder_item) {
        ((ViewHolder_item) holder).match_time.setText(NFD.getMatch_time());
        ((ViewHolder_item) holder).match_result.setText(NFD.getMatch_result());
        ((ViewHolder_item) holder).team_home.setText(NFD.getTeam_home());
        ((ViewHolder_item) holder).team_away.setText(NFD.getTeam_away());
        ((ViewHolder_item) holder).match_status.setText(NFD.getMatch_status());
        Glide.with(context).load(NFD.getTeam_home_logo()).into(  ((ViewHolder_item) holder).team_home_logo);
        Glide.with(context).load(NFD.getTeam_away_logo()).into(  ((ViewHolder_item) holder).team_away_logo);
    }
    else if (holder instanceof ViewHolder_header) {
        ((ViewHolder_header) holder).tournament_name.setText(NFD.getTournament_name());
    }
}

@Override
public int getItemViewType(int position) {
    super.getItemViewType(position);
    if(position == 0) {
        return View_Header;
    }else  {
        return View_Item;
    }
}

@Override
public int getItemCount() {
    return footballresults_data.size()+1;
}

public static class ViewHolder_item extends RecyclerView.ViewHolder {

    public TextView match_time;
    public TextView match_result;
    public TextView team_home;
    public TextView team_away;
    public TextView match_status;
    public ImageView team_home_logo;
    public ImageView team_away_logo;

    public ViewHolder_item(View itemView) {
        super(itemView);
        match_time = (TextView)itemView.findViewById(R.id.match_time);
        match_result = (TextView)itemView.findViewById(R.id.match_res);
        team_home = (TextView)itemView.findViewById(R.id.match_th);
        team_away = (TextView)itemView.findViewById(R.id.match_ta);
        match_status = (TextView)itemView.findViewById(R.id.match_status);
        team_home_logo = (ImageView)itemView.findViewById(R.id.logo_th);
        team_away_logo = (ImageView)itemView.findViewById(R.id.logo_ta);
    }
}

public static class ViewHolder_header extends RecyclerView.ViewHolder {

    public TextView tournament_name;

    public ViewHolder_header(View itemView) {
        super(itemView);
        tournament_name = (TextView)itemView.findViewById(R.id.tournament_n);
    }
}
}
Yevgen
  • 93
  • 1
  • 1
  • 8

1 Answers1

0

Override getItemViewType (int position) return the appropriate type based on position and then inflate a different layout for header in onCreateViewHolder.

In Adapter

private static int View_Header =0;
private static int View_Item = 1;

Then

@Override
public int getItemViewType (int position) {
    // position 0 return header type
    if(position == 0) {

        return View_Header;

    }else  {

        return View_Item;
    }

}

Then

// add 1 to the list 
// total items is item in list + 1 for header
@Override
public int getItemCount() {
    return footballresults_data.size()+1;
}

Then

@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

    RecyclerView.ViewHolder holder = null;
    if(viewType == View_Item) {
        View view = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.card_match, parent, false);
        holder = new ViewHolder_Item(view);

    }else if(viewType == View_Header) {
         // inflate header layout
        View view = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.header_layout, parent, false);
        holder = new ViewHolder_header(view);

    }
 return holder;
 }

Then

@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {

    if (holder instanceof ViewHolder) {
         // bind row items items

    }
    // create a separate viewholder class for header
    else if( holder instanceof ViewHolder_header){ 
        // bind header item
    }

If you are looking for header and sub items (grouping items under a header) have a look at https://stackoverflow.com/a/42976078/653856. But the logic remains the same

Raghunandan
  • 132,755
  • 26
  • 225
  • 256
  • I tried to make by your way but happened error (java.lang.IndexOutOfBoundsException: Invalid index 0, size is 0) in line: FootballResultsData NFD = footballresults_data.get(position) Where I made a mistake? Current code is in my post. – Yevgen Dec 07 '17 at 19:25
  • @Yevgen check the link posted in the answer. – Raghunandan Dec 08 '17 at 07:16
  • Yes, I found out my mistakes and it's working now! Thanks. Though sometimes appears this error in one case of five (approximately). – Yevgen Dec 08 '17 at 08:59
  • @Yevgen note: my code is for adding header at the top of list. If you want header for a group of items you need to change logic `getItemViewType`. – Raghunandan Dec 08 '17 at 09:05