You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

GridView展示图片与视频:区分显示及添加视频时长的技术求助

解决Gallery中图片/视频区分及视频时长显示问题

咱们一步一步来搞定这个问题——核心思路就是先从数据源区分媒体类型,再在GridView的Item里针对性展示标识和时长,话不多说直接上方案:


第一步:完善数据模型,区分图片与视频

首先得给每个媒体文件建个数据类,存路径、类型、时长这些关键信息:

public class MediaItem {
    private String filePath;
    private boolean isVideo;
    private long durationMs; // 视频时长(毫秒)

    // 构造方法、Getter/Setter
    public MediaItem(String filePath, boolean isVideo, long durationMs) {
        this.filePath = filePath;
        this.isVideo = isVideo;
        this.durationMs = durationMs;
    }

    public String getFilePath() { return filePath; }
    public boolean isVideo() { return isVideo; }
    public long getDurationMs() { return durationMs; }
}

然后在加载媒体文件时,通过MediaStore(比直接扫文件更可靠)判断类型并获取视频时长:

private void loadMediaContent() {
    List<MediaItem> mediaList = new ArrayList<>();
    // 查询图片+视频的投影字段
    String[] projection = {
            MediaStore.Files.FileColumns.DATA,
            MediaStore.Files.FileColumns.MEDIA_TYPE,
            MediaStore.Video.Media.DURATION
    };
    // 筛选条件:只取图片和视频
    String selection = MediaStore.Files.FileColumns.MEDIA_TYPE + "="
            + MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE
            + " OR " + MediaStore.Files.FileColumns.MEDIA_TYPE + "="
            + MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO;

    Cursor cursor = getContentResolver().query(
            MediaStore.Files.getContentUri("external"),
            projection,
            selection,
            null,
            MediaStore.Files.FileColumns.DATE_ADDED + " DESC"
    );

    if (cursor != null) {
        while (cursor.moveToNext()) {
            String path = cursor.getString(cursor.getColumnIndex(MediaStore.Files.FileColumns.DATA));
            int mediaType = cursor.getInt(cursor.getColumnIndex(MediaStore.Files.FileColumns.MEDIA_TYPE));
            boolean isVideo = mediaType == MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO;
            long duration = isVideo ? cursor.getLong(cursor.getColumnIndex(MediaStore.Video.Media.DURATION)) : 0;

            mediaList.add(new MediaItem(path, isVideo, duration));
        }
        cursor.close();
    }
    // 把数据传给Adapter更新UI
    ((MediaGridAdapter) yourGridView.getAdapter()).updateData(mediaList);
}

第二步:修改GridView的Item布局

给Item加播放图标(仅视频显示)和时长文本(仅视频显示),比如item_media_grid.xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <!-- 媒体缩略图 -->
    <ImageView
        android:id="@+id/iv_thumbnail"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scaleType="centerCrop"/>

    <!-- 视频播放图标 -->
    <ImageView
        android:id="@+id/iv_play_mark"
        android:layout_width="48dp"
        android:layout_height="48dp"
        android:layout_centerInParent="true"
        android:src="@drawable/ic_play_circle"
        android:visibility="gone"/>

    <!-- 视频时长文本 -->
    <TextView
        android:id="@+id/tv_duration"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentEnd="true"
        android:padding="4dp"
        android:background="#80000000"
        android:textColor="#FFFFFF"
        android:textSize="12sp"
        android:visibility="gone"/>
</RelativeLayout>

第三步:升级GridView Adapter的逻辑

在Adapter里根据MediaItem的类型控制视图显示,同时格式化时长:

public class MediaGridAdapter extends BaseAdapter {
    private Context mContext;
    private List<MediaItem> mMediaList;
    private Glide mGlide; // 用Glide加载缩略图,效率更高

    public MediaGridAdapter(Context context) {
        mContext = context;
        mMediaList = new ArrayList<>();
        mGlide = Glide.with(context);
    }

    // 更新数据的方法
    public void updateData(List<MediaItem> newList) {
        mMediaList.clear();
        mMediaList.addAll(newList);
        notifyDataSetChanged();
    }

    // 省略getCount、getItem、getItemId方法

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder;
        if (convertView == null) {
            convertView = LayoutInflater.from(mContext).inflate(R.layout.item_media_grid, parent, false);
            holder = new ViewHolder();
            holder.ivThumbnail = convertView.findViewById(R.id.iv_thumbnail);
            holder.ivPlayMark = convertView.findViewById(R.id.iv_play_mark);
            holder.tvDuration = convertView.findViewById(R.id.tv_duration);
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }

        MediaItem item = mMediaList.get(position);
        // 加载缩略图:Glide自动支持视频第一帧加载
        mGlide.load(new File(item.getFilePath()))
                .placeholder(R.drawable.ic_media_placeholder)
                .into(holder.ivThumbnail);

        if (item.isVideo()) {
            // 显示视频专属元素
            holder.ivPlayMark.setVisibility(View.VISIBLE);
            holder.tvDuration.setVisibility(View.VISIBLE);
            holder.tvDuration.setText(formatDuration(item.getDurationMs()));
        } else {
            // 隐藏视频元素,只显示图片
            holder.ivPlayMark.setVisibility(View.GONE);
            holder.tvDuration.setVisibility(View.GONE);
        }

        return convertView;
    }

    // 格式化时长为 mm:ss 格式
    private String formatDuration(long durationMs) {
        long seconds = durationMs / 1000;
        long minutes = seconds / 60;
        seconds = seconds % 60;
        return String.format("%02d:%02d", minutes, seconds);
    }

    static class ViewHolder {
        ImageView ivThumbnail;
        ImageView ivPlayMark;
        TextView tvDuration;
    }
}

第四步:在Gallery Activity中初始化

把Adapter和GridView绑定,然后加载媒体内容:

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_share);
    // ... 其他初始化代码(比如Spinner、BottomNavigation)
    GridView mediaGridView = findViewById(R.id.your_grid_view_id);
    MediaGridAdapter adapter = new MediaGridAdapter(this);
    mediaGridView.setAdapter(adapter);
    
    // 记得动态申请存储权限(Android 6.0+)
    if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)
            == PackageManager.PERMISSION_GRANTED) {
        loadMediaContent();
    } else {
        ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, 1001);
    }
}

// 权限回调
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if (requestCode == 1001 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
        loadMediaContent();
    }
}

额外优化小Tips

  • 用Glide代替Picasso,Glide对视频缩略图的支持更稳定,还能缓存提升加载速度
  • 如果追求极致性能,可以用MediaStore提供的缩略图接口,避免加载完整文件
  • 可以给视频Item加个轻微的圆角或者边框,进一步区分图片

内容的提问来源于stack exchange,提问作者lllllllllllllll

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 10:08:17