Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

Android Android Lists and Adapters (2015) Lists with RecyclerViews Using a Layout Manager

Slava Fleer
Slava Fleer
6,086 Points

Hello guys (and girls if you here =) ) I want to change text just on first item of the list. how i can do it?

I am doing day button with recyclerview. it is work ok and everything fine. but i want to change first day of the week to "Today". How can I choose to act differently on 1st (or other) item/s from rest of list?

thanks.

3 Answers

Hi Slava,

That should be possible, yes.

The day is set in the onItemClickListener we talked about yesterday. That receives a parameter called position.

So, where you are setting the label with String dayOfTheWeek = mDays[position].getDayOfTheWeek(); you could surround that line with an if statement such that if the position is zero, set the label to today, else do what it's doing now.

Does that make sense? I'm assuming that the first element is indexed by a zero; best check the documentation.

Steve.

Slava Fleer
Slava Fleer
6,086 Points

I don't think you can choose something different with adapter position. Course it working as black box for us (for me anyway =) ) But I could enter "if" in Day[] where we getting json data at firth time. edited: ups. forgot that getDayOfTheWeek is in day class. =(. So as i see the problem I'm must to compare in getDayOfTheWeek the time to local time and if difference less than hour than it is today ? Or is it as scratching right hear with left arm ? =)

Hi Slava,

I thought I'd give that a go myself and just put some Toast pop-ups in the Activity to show what the position variable holds.

Sure enough, the top item is position == 0, the second is position == 1 and so on. So there's no reason why you can't amend your code to change the label text based on the position.

Here is my amended setOnItemClickListener where the internal onItemClick method receives a position as a parameter.

Good luck!

Steve.

        mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                Toast.makeText(DailyForecastActivity.this, "Position is: " + position, Toast.LENGTH_LONG).show();
                String dayOfTheWeek = mDays[position].getDayOfTheWeek();
                String conditions = mDays[position].getSummary();
                String highTemp = mDays[position].getTemperatureMax() + "";
                String message = String.format("At position, %s, on %s the high will be %s and it will be %s",
                        position,
                        dayOfTheWeek,
                        highTemp,
                        conditions);
                Toast.makeText(DailyForecastActivity.this, message, Toast.LENGTH_LONG).show();
            }
        });
Slava Fleer
Slava Fleer
6,086 Points

the problem, that i don't need onItemClick, but before it, when i showing the RecyclerView items on the screen. there i didn't found where i could choose position. =(

Ah, right ... sorry - that's my mistake. You want the list to have "Today" at the top, rather than the Toast.

I shall see if I can work that out!

Steve.

Boban Talevski
Boban Talevski
24,793 Points

I have posted an answer in another thread about this, but I'll post it here as well. Note that this is concerning changing the first item in the hourly forecast activity to say "Now" instead of the actual hour. It's pretty much the same thing as saying "Today" instead of the current day in the daily forecast, I just haven't gotten to recreating the daily forecast with a recycler view yet.


I see this didn't get an answer for a while and it's an interesting feature which I guess comes to mind naturally after implementing the same thing with the ListView, though it's a bit trickier here.

So, for anyone interested about this, I guess there are various solutions. The very simple but not so elegant one seems to be this: HourAdapter.java

package com.example.bobantalevski.stormy.adapters;

import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

import com.example.bobantalevski.stormy.R;
import com.example.bobantalevski.stormy.weather.Hour;

import butterknife.BindView;
import butterknife.ButterKnife;

/**
 * Created by Boban Talevski on 9/20/2017.
 */

public class HourAdapter extends RecyclerView.Adapter<HourAdapter.HourViewHolder> {

    private Hour[] hours;

    public HourAdapter(Hour[] hours) {
        this.hours = hours;
    }

    @Override
    public HourViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.hourly_list_item, parent, false);
        HourViewHolder viewHolder = new HourViewHolder(view);

        return viewHolder;
    }

    @Override
    public void onBindViewHolder(HourViewHolder holder, int position) {
        if (position == 0) {
            holder.bindHourNow(hours[position]);
        } else {
            holder.bindHour(hours[position]);
        }
    }

    @Override
    public int getItemCount() {
        return hours.length;
    }

    public class HourViewHolder extends RecyclerView.ViewHolder {

        @BindView(R.id.timeLabel) TextView timeLabel;
        @BindView(R.id.summaryLabel) TextView summaryLabel;
        @BindView(R.id.temperatureLabel) TextView temperatureLabel;
        @BindView(R.id.iconImageView) ImageView iconImageView;

        public HourViewHolder(View itemView) {
            super(itemView);
            ButterKnife.bind(this, itemView);
        }

        public void bindHour(Hour hour) {
            timeLabel.setText(hour.getHour());
            summaryLabel.setText(hour.getSummary());
            temperatureLabel.setText(Integer.toString(hour.getTemperature()));
            iconImageView.setImageResource(hour.getIconId());
        }

        public void bindHourNow(Hour hour) {
            timeLabel.setText("Now");
            summaryLabel.setText(hour.getSummary());
            temperatureLabel.setText(Integer.toString(hour.getTemperature()));
            iconImageView.setImageResource(hour.getIconId());
        }
    }
}

So, we have to start at a point where we can access the index/position to check if it's zero. The only place where we have this option is in the onBindViewHolder method. Then, inside that method, we check for that condition and depending on whether it's zero or not, we either call the usual bindHour method inside the HourViewHolder class, or if it's indeed zero, we call a special newly created "bindHour type" method called bindHourNow, which exists only for this purpose (hence the not so elegant solution assumption). In that specific method we just set the timeLabel text to "Now" and set the other views as usual.

Now, this can be maybe improved in a way to modify the bindHour method to accept a second boolean argument (isZero) which we will pass from the onBindViewHolder method depending on whether the position is zero or not, and depending on that argument we set the timeLabel text to either "Now" or the actual value inside the hour object without the need for creating a special new method for this purpose.

Both of these options are working for this particular project and the data we have. This is the second (assumingly more elegant) way:

package com.example.bobantalevski.stormy.adapters;

import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

import com.example.bobantalevski.stormy.R;
import com.example.bobantalevski.stormy.weather.Hour;

import butterknife.BindView;
import butterknife.ButterKnife;

/**
 * Created by Boban Talevski on 9/20/2017.
 */

public class HourAdapter extends RecyclerView.Adapter<HourAdapter.HourViewHolder> {

    private Hour[] hours;

    public HourAdapter(Hour[] hours) {
        this.hours = hours;
    }

    @Override
    public HourViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.hourly_list_item, parent, false);
        HourViewHolder viewHolder = new HourViewHolder(view);

        return viewHolder;
    }

    @Override
    public void onBindViewHolder(HourViewHolder holder, int position) {
        holder.bindHour(hours[position], position == 0);
    }

    @Override
    public int getItemCount() {
        return hours.length;
    }

    public class HourViewHolder extends RecyclerView.ViewHolder {

        @BindView(R.id.timeLabel) TextView timeLabel;
        @BindView(R.id.summaryLabel) TextView summaryLabel;
        @BindView(R.id.temperatureLabel) TextView temperatureLabel;
        @BindView(R.id.iconImageView) ImageView iconImageView;

        public HourViewHolder(View itemView) {
            super(itemView);
            ButterKnife.bind(this, itemView);
        }

        public void bindHour(Hour hour, boolean isZero) {
            timeLabel.setText(isZero ? "Now" : hour.getHour());
            summaryLabel.setText(hour.getSummary());
            temperatureLabel.setText(Integer.toString(hour.getTemperature()));
            iconImageView.setImageResource(hour.getIconId());
        }
    }
}

We just have to realize that (some of) these methods and arguments are not set in stone and one can assume that onBindViewHolder is called by the android system, so we probably can't mess with its arguments. But bindHour on the other hand, seems to exist only for the purpose of being called from onBindViewHolder and if we add a second method of that type, or change its arguments, we can do this as long as we don't break the core functionality which is to populate the views for a particular list item with the appropriate data from our data model.