Change ImageView in a GridView Programmatically

2020-03-30 06:26发布

问题:

I've set up a grid of ImageViews with TextView overlays. My ImageAdapter code is as follows:

    public View getView(int position, View convertView, ViewGroup parent) {
    ImageView imageView;
    View grid;
    LayoutInflater inflater = (LayoutInflater) mContext
            .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    if (convertView == null) {
        grid = new View(mContext);
        grid = inflater.inflate(R.layout.image, null);
        TextView textView = (TextView)grid.findViewById(R.id.mastery_text);

        imageView = (ImageView)grid.findViewById(R.id.mastery_image);
        grid.setLayoutParams(new GridView.LayoutParams(150, 150));
        imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
        grid.setPadding(8, 8, 8, 8);
        grid.setBackgroundResource(R.color.orange);

        imageView.setImageResource(mThumbIds[position]);            

    } else {
        grid = (View) convertView;
    }

    return grid;
}

The corresponding XML layout for my ImageAdapter is this:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/layout_practitioner" 
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <ImageView 
        android:id="@+id/mastery_image"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scaleType="centerCrop"
    />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:layout_gravity="bottom"
        android:background="#bbffffff"
        android:focusable="false"
        android:focusableInTouchMode="false" >

        <TextView android:id="@+id/mastery_text"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="0dp"
            android:textColor="@color/black"
            android:gravity="bottom|center"
            android:textSize="12sp"
            android:textAllCaps="true"
            android:paddingBottom="0dp"
            android:text="3/3"
            />

    </LinearLayout>
</FrameLayout>

XML code for my GridView (activity class):

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">

    <GridView xmlns:android="http://schemas.android.com/apk/res/android"
        android:paddingTop="@dimen/activity_vertical_margin"
        android:paddingLeft="@dimen/activity_horizontal_margin"
        android:paddingRight="@dimen/activity_horizontal_margin"
        android:id="@+id/gridview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:numColumns="4"
        android:verticalSpacing="10dp"
        android:horizontalSpacing="10dp"
        android:stretchMode="columnWidth"
        android:gravity="center" />

</LinearLayout>

Here is the onCreate method of my main activity:

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_masteries);

    GridView gridview = (GridView) findViewById(R.id.gridview);

    ImageAdapter adapter = new ImageAdapter(this);
    gridview.setAdapter(adapter);

    gridview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
        public void onItemClick(AdapterView<?> parent, View v,
                                int position, long id) {
            Toast.makeText(Masteries.this, "" + position,
                    Toast.LENGTH_SHORT).show();
        }
    });
}

I want to, after initializing the grid with the images, change one of the ImageViews from my activity class, given its position on the grid. How would I do that?

I'm not asking to change the image in response to an onItemClick. Thanks in advance!

Edit: I'm thinking of creating a changeImage(int position, int imageId) method in my Adapter and calling that from my activity class. Is that the right approach?

回答1:

In your adapter:

public void updateImage(int position, int resourceId)
{
    mThumbIds[position] = resourceId;
    notifyDataSetChanged();
}

In your activity:

mAdapter.updateImage(<position>, <image_resource_id>);

Notes

  1. You will have to make the adapter a member of your activity
  2. The main idea is that you modify the backing data and and notify the GridView that this has changed and it is time to be redrawn
  3. Your getView() method implementation needs a lot of improvement. It will cause lots of bugs once the system starts recycling the views (the convertView parameter comes in != null for a position different than it was used for last time)

Here's a sketch of how your getView() should look like:

@Override
public View getView(int position, View convertView, ViewGroup parent)
{
    ViewHolder viewHolder;
    LayoutInflater inflater = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    if (convertView == null) {
        convertView = inflater.inflate(R.layout.image, parent, false);
        // next three lines would not be necessary if:
        //  a) it is the same for every item;
        //  b) you inflate properly (using the parent);
        //  c) you specify this in the item's xml (R.layout.image)
        convertView.setLayoutParams(new GridView.LayoutParams(150, 150));
        convertView.setPadding(8, 8, 8, 8);
        convertView.setBackgroundResource(android.R.color.holo_red_light);

        viewHolder = new ViewHolder();
        viewHolder.mTextView = (TextView)convertView.findViewById(R.id.mastery_text);
        viewHolder.mImageView = (ImageView)convertView.findViewById(R.id.mastery_image);
        // this could also be set in xml perhaps
        viewHolder.mImageView.setScaleType(ImageView.ScaleType.CENTER_CROP);

        convertView.setTag(viewHolder);
    } else {
        viewHolder = (ViewHolder)convertView.getTag();
    }

    // update the values every time we are being asked to update the item,
    // because the item might have been reused from a different position
    viewHolder.mImageView.setImageResource(mThumbIds[position]);
    //viewHolder.mTextView.setText("myText");

    return convertView;
}


public static class ViewHolder
{
    TextView mTextView;
    ImageView mImageView;
}


回答2:

You can set a unique id to each ImageView using names (See here) or even integer numbers with a sequence or something (increasing at each image you put in the view).

Another good way to do this is using the tags, with setTag() and getTag(). This question has a good answer: What is the main purpose of setTag() getTag() methods of View?