Инициализировать RelativeLayout в этом getView, генерация программного представления
Я использую getView в адаптере, где я создаю изображение и делаю его равным 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
) и добавьте imageview и playbutton imageview в это конвертируемое изображение
Как я могу это сделать? Требуется изменить это утверждение, но я не уверен, как инициализировать все повторно используемые представления
} else { // Otherwise re-use the converted view
imageView = (ImageView) convertView;
}
2 ответа
Я бы сделал твой getView()
всегда возвращать RelativeLayout
объект (который я называю containerView
ниже) к которому вы добавляете ImageView(s)
как дети.
Единственная сложность здесь заключается в том, что вам нужно дать эти дочерние идентификаторы, чтобы вы могли извлечь их из переработанного convertView
потом. Обратите внимание, что я использовал встроенный, статический View.generateViewId()
для этого это уровень API 17. Если вам нужно, чтобы он работал до уровня API-17, вы можете создавать свои собственные идентификаторы, используя уникальные целые числа (например, 1, 2 и т. д.) - просто убедитесь, что они не лучше чем 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;
}
Обратите внимание, что вам не нужен уникальный идентификатор представления для каждой ячейки в вашей сетке. Скорее, вам просто нужно это для каждого типа дочернего представления, к которому вы, возможно, захотите получить доступ, используя findViewById()
, Так что в вашем случае вам, вероятно, понадобятся только два уникальных идентификатора. Так как представления автоматически генерируются из ваших файлов макета XML в ваш R.java
как правило, они очень большие, мне было удобно просто использовать низкие числа для моих сгенерированных вручную идентификаторов (как показано выше).
Я думаю, что лучший подход здесь будет использовать адаптер, который возвращает различные типы представлений (путем переопределения getViewTypeCount()
а также getItemViewType()
), например, как описано в этом ответе.
Таким образом, вам вообще не нужно программно изменять возвращаемые представления. Просто определите два XML-макета и надуйте / повторно используйте один или другой в зависимости от того, есть ли у элемента в этой позиции видео или нет.
Мало того, что это будет яснее, у вас не будет потери производительности при "преобразовании" одного представления в другое всякий раз, когда видеоряд будет представлен как convertView
за другой предмет без такового или наоборот