1

I'm trying to display a ListView with coloured background item. Every row should have different gradient background. I've searched for some time but couldn't fix my problem. Every row has same background now - last saved profile. Moreover, I failed to set gradient as background of TextView that uses rounded.xml as background. Thanks for any help.

Screenshot of my list

Here's my CustomAdapter:

public class CustomAdapterProfiles extends ArrayAdapter<Profile> {

    private static final String TAG = "MyActivity";
    ArrayList<Profile> myArrayList = null;
    PaintDrawable paint;

    int[] arrColors;
    int numColors;
    float[] result;

    Profile i;

    CustomAdapterProfiles(Context context, ArrayList<Profile> menuAdapter){
        super(context, R.layout.customrow , menuAdapter);
        this.myArrayList = menuAdapter;
    }


    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        LayoutInflater listInflater = LayoutInflater.from(getContext());
        View customView = listInflater.inflate(R.layout.customrow, parent, false);

        i = myArrayList.get(position);
        String singleItem = i.getObjectName();
        TextView mobileText = (TextView) customView.findViewById(R.id.listID);
        mobileText.setText(singleItem);

        numColors = i.getArrayList().size();
        arrColors = new int[i.getArrayList().size()];

        if (numColors>1) {

            //positions of colors defined by user
            result = new float[numColors];
            for (int a = 0; a < numColors; a++) {
                result[a] = (float) i.getGradients().get(a);
            }

            //make sure user didnt write error values (not fixed yet)
            result[0]=0;
            result[numColors - 1] = 1;

            //colors
            for (int j = 0; j < numColors; j++) {
                arrColors[j] = Integer.parseInt(i.getArrayList().get(j).toString(), 16) + 0xFF000000;
            }

            ShapeDrawable.ShaderFactory shaderFactory = new ShapeDrawable.ShaderFactory() {
                @Override
                public Shader resize(int width, int height) {
                    LinearGradient linearGradient = new LinearGradient(0, 0, width, height,
                            arrColors, //pouzity array farieb
                            result,
                            Shader.TileMode.REPEAT);
                    return linearGradient;
                }
            };
            paint = new PaintDrawable();
            paint.setShape(new RectShape());
            paint.setShaderFactory(shaderFactory);

            mobileText.setBackgroundDrawable((Drawable) paint);
        }
        else {
            //cant set shaderFactory becouse it needs 2 or more colors
            mobileText.getBackground().setColorFilter(Color.parseColor("#" + i.getArrayList().get(0).toString()), PorterDuff.Mode.SRC_ATOP);
        }

        return customView;
    }
}
Reaz Murshed
  • 23,691
  • 13
  • 78
  • 98

2 Answers2

0

Remove the background set from the layout of your list item. From your code, I see the layout you're using for each list item is customrow.xml. You might have a rounded.xml background there. Remove that line.

Now about showing the proper colour for each list item...

As from the picture I can see you're setting some gradient, so I guess you can generate the gradient correctly.

Now as I can see from your code, you're setting the same colour for each item of your ListView. So I guess you've misunderstood the behaviour of the getView() function. So here I'm clearing the idea.

getView() is called for each item of the ListView once it is shown in the screen. Suppose, you've 20 items in your list. Now when the list is loaded first time, let us guess first 7 items are shown in the screen and you've to scroll to see the other items.

Now here's how ListView works to re-cycle the views generated already. ListView doesn't populate all your 20 items at a time. Instead, it populates the first 7 which are shown in the screen. So first time, the getView() function is called 7 times to populate each of the item visible in the screen. When you scroll the list, the getView() function is called again for each of the new visible items in the list.

Hope you have an idea from the explanation. Now, here's how you can solve your problem.

Let us take an array of colours which are defined by the user.

int[] arrColors = {/* ..get the user input and populate the colour array outside of the adapter. */};
int numColors = 10; // I've just set a default value

Now here's a pseudo code of your getView function.

@Override
public View getView(int position, View convertView, ViewGroup parent) {

    LayoutInflater listInflater = LayoutInflater.from(getContext());
    View customView = listInflater.inflate(R.layout.customrow, parent, false);

    // ... Set the text
    // position of colors defined by user
    // ... Get the user defined colour here. 
    Color color = arrColors[position];

    // Now modify the colour as you wish
    Paint paint = prepareTheBackground();

    // Now set the colour as background
    mobileText.setBackgroundDrawable((Drawable) paint);

    return customView;
}
Reaz Murshed
  • 23,691
  • 13
  • 78
  • 98
  • Thanks for response ! :) The point of using rounded.xml as background of customrow.xml - i wanted to have the final result be rounded textview with gradient background color . But that is not big issue here. The pseudocode you posted is basically the code i have. It sets gradient backgrounds for each item same. I wanted it to be unique :/ Every item has object in it that contains colors for gradient. After i add new item, all items have background of the last added. – Martin Voroňák Aug 27 '16 at 20:37
  • The key thing is to set the background for each list item right? From your code I see that, you're setting the same background color for all items. My idea is to populate an array first with the desired colors and then get the `position` of the list view in `getView()` function and fetch the exact color from that array. Please check your code again. – Reaz Murshed Aug 28 '16 at 02:09
0

The biggest problem (i guess it was this) was using ArrayAdapter instead of BaseAdapter. I have tried (as noob android programmer) many things and tutorials, but after i tried this: enter link description here it worked. Also, as you can see, i have found solution to rounded textview (marked in code below "---"). Name of row items are set to "" so you can not see the names.

enter image description here

public class CustomListAdapter extends BaseAdapter {
private Context context; //context
private ArrayList<Profile> items; //data source of the list adapter

//public constructor
public CustomListAdapter(Context context, ArrayList<Profile> items) {
    this.context = context;
    this.items = items;
}

@Override
public int getCount() {
    return items.size(); //returns total of items in the list
}

@Override
public Object getItem(int position) {
    return items.get(position); //returns list item at the specified position
}

@Override
public long getItemId(int position) {
    return position;
}

public void updateResults(ArrayList<Profile> results) {
    items = results;
    //Triggers the list update
    notifyDataSetChanged();
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    ViewHolder viewHolder;

    if (convertView == null) {
        convertView = LayoutInflater.from(context).inflate(R.layout.customrow, parent, false);
        viewHolder = new ViewHolder(convertView);
        convertView.setTag(viewHolder);
    } else {
        viewHolder = (ViewHolder) convertView.getTag();
    }

    // get current item to be displayed
    Profile currentItem = (Profile) getItem(position);
    viewHolder.itemName.setText(currentItem.getObjectName());


    int numColors = currentItem.getArrayList().size();


    if (numColors > 1) {

        int[] arrColors = new int[numColors];

        //positions of colors defined by user
        final float[] result = new float[numColors];
        for (int a = 0; a < numColors; a++) {
            result[a] = (float) currentItem.getGradients().get(a);
        }

        //make sure user didnt write error values (not fixed yet)
        result[0] = 0;
        result[numColors - 1] = 1;

        //colors
        for (int j = 0; j < numColors; j++) {
            arrColors[j] = Integer.parseInt(currentItem.getArrayList().get(j).toString(), 16) + 0xFF000000;
        }

        final int[] finalArrColors = arrColors;

        ShapeDrawable.ShaderFactory shaderFactory = new ShapeDrawable.ShaderFactory() {
            @Override
            public Shader resize(int width, int height) {
                LinearGradient linearGradient = new LinearGradient(0, 0, width, height,
                        finalArrColors, //pouzity array farieb
                        result,
                        Shader.TileMode.REPEAT);
                return linearGradient;
            }
        };

        // --- rounded textView !
        PaintDrawable paint = new PaintDrawable();
        paint.setShape(new RectShape());
        paint.setShaderFactory(shaderFactory);

        paint.setCornerRadius(100);
        // --- end of rounded textView code

        viewHolder.itemName.setBackgroundDrawable(paint);
    }
    else if (numColors == 1) {
        //not important
    }
    else {
        viewHolder.itemName.setText("empty object");
    }

    return convertView;
}

private class ViewHolder {
    TextView itemName;

    public ViewHolder(View view) {
        itemName = (TextView) view.findViewById(R.id.listID);
    }
}

}

Calling the BaseAdapter:

CustomListAdapter adapter = new CustomListAdapter(this, profiles); ListView menuListView = (ListView) findViewById(R.id.listViewHS); menuListView.setAdapter(adapter); adapter.updateResults(profiles);

Profile Class:

public class Profile implements Serializable {

private String objectName;
private ArrayList<String> arrayColorList;
private ArrayList<Float> gradients;

public Profile(String objectName, ArrayList<String> arrayList, ArrayList<Float> gradients){
    this.objectName=objectName;
    this.arrayColorList=arrayList;
    this.gradients=gradients;
}

public String getObjectName() {
    return objectName;
}

public ArrayList<String> getArrayList() {
    return arrayColorList;
}

public ArrayList<Float> getGradients() {
    return gradients;
}

}