2

我在适配器中使用 getView,我正在创建一个 imageview 并使其等于之前已经初始化视图的 convertView。它包含图像缩略图,其中一些代表视频。

    @Override
    public View getView(int position, View convertView, ViewGroup container) {
        // First check if this is the top row

        if (position < mNumColumns) {
            if (convertView == null) {
                convertView = new View(mContext);
            }
            // Set empty view with height of ActionBar
            //convertView.setLayoutParams(new AbsListView.LayoutParams(
            //      LayoutParams.MATCH_PARENT, mActionBarHeight));
            return convertView;
        }

        // Now handle the main ImageView thumbnails
        ImageView imageView;
        if (convertView == null) { // if it's not recycled, instantiate and initialize
            imageView = new RecyclingImageView(mContext);
            imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
            imageView.setLayoutParams(mImageViewLayoutParams);
        } else { // Otherwise re-use the converted view
            imageView = (ImageView) convertView;
        }

        // Check the height matches our calculated column width
        if (imageView.getLayoutParams().height != mItemHeight) {
            imageView.setLayoutParams(mImageViewLayoutParams);
        }

        imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);

        if(images.get(position - mNumColumns).getUriString().contains("video")){
            //display video icon
        }
        else
        {
            //don't display video icon
        }

        // Finally load the image asynchronously into the ImageView, this also takes care of
        // setting a placeholder image while the background thread runs
        if (images != null && !images.isEmpty())
            mImageFetcher.loadImage(images.get(position - mNumColumns).getUriString()/*.imageUrls[position - mNumColumns]*/, imageView);
        return imageView;
    }

缩略图上没有“播放”按钮来指定它们是视频,因此在这些情况下,我需要以编程方式添加播放按钮。

通常我使用带有膨胀布局的视图模式,在这种情况下我不会这样做,因为我实际上不希望内存中有一些东西。

因此,我想以编程方式将 RelativeLayout 作为每个单元格(mRelativeLayout = (RelativeLayout)convertView)的根视图,并将图像视图和播放按钮图像视图添加到该转换视图中

我怎么做?它需要修改此语句,但我不确定如何初始化所有重用的视图

   } else { // Otherwise re-use the converted view
            imageView = (ImageView) convertView;
        }
4

2 回答 2

3

我认为这里最好的方法是使用返回不同类型视图的适配器(通过覆盖getViewTypeCount()and getItemViewType()),例如本答案中所述。

这样,您根本不需要以编程方式更改返回的视图。只需定义两个 XML 布局并根据该位置的项目是否有视频来膨胀/重用一个或另一个。

这不仅会更清晰,而且当提供视频行时,您不会因为没有视频行而将一个视图“转换”为另一个视图而导致性能损失,convertView反之亦然

于 2014-10-14T20:02:51.960 回答
2

我会让你getView()总是返回一个RelativeLayout对象(我containerView在下面调用它),你将它添加ImageView(s)为孩子。

这里唯一的复杂之处是您需要为这些孩子提供标识符,以便convertView以后可以从回收站中检索它们。请注意,我为此使用了内置的静态View.generateViewId(),即 API 级别 17。如果您需要它在 API 级别 17 之前工作,您可以使用唯一整数(例如 1、2 等)创建自己的 ID。 ) - 只要确保它们不大于0x0FFFFFF. 更新: 我在下面添加了用于此的代码。

请参阅我在以下几点中添加的评论。

@Override
public View getView(int position, View convertView, ViewGroup container) {
    // First check if this is the top row
    if (position < mNumColumns) {
        if (convertView == null) {
            convertView = new View(mContext);
        }
        // Set empty view with height of ActionBar
        //convertView.setLayoutParams(new AbsListView.LayoutParams(
        //      LayoutParams.MATCH_PARENT, mActionBarHeight));
        return convertView;
    }

    // Now handle the main ImageView thumbnails
    RelativeLayout containerView;
    ImageView imageView;
    ImageView videoIconView;   // TODO:  or whatever type you want to use for this...
    if (convertView == null) { // if it's not recycled, instantiate and initialize
        containerView = new RelativeLayout(mContext);
        // TODO:  The layout params that you used for the image view you probably 
        // now want to use for the container view instead...
        imageView.setLayoutParams(mImageViewLayoutParams);   // If so, you can change their name...

        imageView = new RecyclingImageView(mContext);
        imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
        //imageView.setLayoutParams(mImageViewLayoutParams);   // This probably isn't needed any more.

        // Generate an Id to use for later retrieval of the imageView...
        // This assumes it was initialized to -1 in the constructor to mark it being unset.
        // Note, this could be done elsewhere in this adapter class (such as in
        // the constructor when mImageId is initialized, since it only
        // needs to be done once (not once per view) -- I'm just doing it here
        // to avoid having to show any other functions.
        if (mImageId == -1) {
            mImageId = View.generateViewId();
        }
        imageView.setId(mImageId);

        containerView.addView(imageView, RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT);

        // NOTE:  At this point, I would personally always just add the video icon
        // as a child of containerView here no matter what (generating another unique 
        // view Id for it, mVideoIconId, similar to how was shown above for the imageView) 
        // and then set it to either VISIBLE or INVISIBLE/GONE below depending on whether
        // the URL contains the word "video" or not.  
        // For example:
        vidoIconView = new <whatever>;
        // TODO:  setup videoIconView with the proper drawable, scaling, etc. here...
        if (mVideoIconId == -1) {
            mVideoIconId = View.generateViewId();
        }
        videoIconView.setId(mVideoIconId);
        containerView.addView(videoIconView, RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
        final RelativeLayout.LayoutParams layout = ((RelativeLayout.LayoutParams)containerView.getLayoutParams());
        layout.addRule(RelativeLayout.LayoutParams.CENTER_HORIZONTAL);   // ... or whatever else you want
        layout.addRule(RelativeLayout.LayoutParams.ALIGN_PARENT_BOTTOM);  // ... or whatever else you want
    } else {
        // Otherwise re-use the converted view
        containerView = (RelativeLayout) convertView;
        imageView = containerView.findViewById(mImageId);
        videoIconView = containerView.findViewById(mVideoIconId);  // see comment above
    }


    // Check the height matches our calculated column width
    if (containerView.getLayoutParams().height != mItemHeight) {
        containerView.setLayoutParams(mImageViewLayoutParams);
    }

    if(images.get(position - mNumColumns).getUriString().contains("video")){
        //display video icon
        // see comment above, here you can probably just do something like:
        videoIconView.setVisibility(View.VISIBLE);
    }
    else
    {
        //don't display video icon
        videoIconView.setVisibility(View.GONE);  // could also use INVISIBLE here... up to you.
    }

    // Finally load the image asynchronously into the ImageView, this also takes care of
    // setting a placeholder image while the background thread runs
    if (images != null && !images.isEmpty())
        mImageFetcher.loadImage(images.get(position - mNumColumns).getUriString()/*.imageUrls[position - mNumColumns]*/, imageView);
    return containerView;
}

更新:
为了回答评论中的问题,我使用了这样的东西(在我的自定义“ViewController”基类中):

private static int s_nextGeneratedId = 1;

/** 
 * Try to do the same thing as View.generateViewId() when using API level < 17.
 * @return Unique integer that can be used with setId() on a View.
 */
protected static int generateViewId() {
    // AAPT-generated IDs have the high byte nonzero; clamp to the range under that.
    if (++s_nextGeneratedId > 0x00FFFFFF)
        s_nextGeneratedId = 1;  // Roll over to 1, not 0.
    return s_nextGeneratedId;
}

请注意,您不需要为网格中的每个单元格提供唯一的视图 ID。相反,您只需要它用于您可能想要使用的每种类型的子视图访问findViewById()。所以在你的情况下,你可能只需要两个唯一的 id。由于从您的 xml 布局文件自动生成的视图 IDR.java通常非常大,因此我发现仅对手动生成的 ID 使用低数字很方便(如上所示)。

于 2014-10-20T18:09:45.630 回答