Android语言基础教程(68)Android高级用户界面设计高级组件之网格视图:别让应用“裸奔”出场!GridView网格视图:给你的App穿上最潮的“格子衫”(附保姆级代码,直接CV)

正文开始:嘿,伙计,是时候聊聊GridView了!

你是不是经常刷着淘宝,看着那些排列整齐、琳琅满目的商品,心里默默点赞:“这界面,舒服!”?或者翻着自己的手机相册,享受着照片被完美归类的快感?

这背后的大功臣,就是我们今天的主角——GridView(网格视图)

你可以把它想象成一个超级有原则的数学课代表,它坚决不允许任何View(视图元素)在它的地盘上乱来,必须行是行,列是列,排排坐,吃果果。它也是Android高级UI组件里的“百搭单品”,一件优秀的“格子衫”,能瞬间提升你App的精致度和实用性。

一、 GridView是谁?它和ListView是亲戚吗?

简单来说,GridView就是一个在二维网格上展示数据的视图组件。

它和ListView(列表视图)确实是“堂兄弟”,都继承自同一个老爸 AbsListView。所以,它们有很多相似之处:

  • 都需要适配器(Adapter):作为数据和视图之间的“月老”,Adapter负责告诉GridView:“数据长这样,你应该怎么把它画出来。”
  • 都支持滚动:数据多了都能滑滑滑。
  • 视图复用机制:超级省内存!只创建一屏能看到的Item(项),滑出去的就回收给新来的用,环保小能手。

那它们最大的区别在哪?方向!

  • ListView:是一维的,垂直的“单身公寓楼”,所有View一个接一个地垂直排列。
  • GridView:是二维的,是“大型小区”,有也有。数据会先从左到右填满一行,然后再换下一行。

所以,当你需要平铺式、并列式地展示内容时(比如表情包选择器、App主菜单、视频封面流),GridView就是你的不二之选。

二、 GridView的核心技能包:怎么把它“驯服”?

想用好GridView,你得摸清它的“脾气”,主要通过XML属性或者Java/Kotlin代码来控制它。

1. 决定你家“格子”长啥样:关键XML属性

  • numColumns最重要的属性! 决定一行有几列。
    • auto_fit:自动填充。配合columnWidth使用,计算屏幕宽度能放下几列,非常智能。
    • 一个具体数字,比如 3:固定3列,就是这么死板但稳定。
  • columnWidth:设置每一列的宽度。和numColumns="auto_fit"是黄金搭档。
  • horizontalSpacing / verticalSpacing:设置格子之间的水平垂直间距。别让格子们挤在一起,要给它们呼吸的空间!
  • stretchMode:当列宽不能完全填满屏幕时,拉伸模式。
    • columnWidth:不拉伸,保持列宽固定(默认)。
    • spacingWidth:拉伸列之间的间距。推荐用这个,能保证你的格子不变形。
  • gravity:每个格子内部内容的对齐方式(比如居中、靠左)。

2. 注入灵魂:Adapter适配器

光有骨架不行,还得有血肉。Adapter就是GridView的灵魂工程师。

// 以Kotlin为例,创建一个简单的ImageAdapter
class ImageAdapter(
    private val context: Context,
    private val imageResIds: List<Int> // 假设是一组图片资源ID
) : BaseAdapter() {

    // 数据集有多少个Item
    override fun getCount(): Int = imageResIds.size

    // 获取指定位置的数据项
    override fun getItem(position: Int): Any = imageResIds[position]

    // 获取每个Item的唯一ID,一般用position就行
    override fun getItemId(position: Int): Long = position.toLong()

    // **最重要的方法!创建和绑定视图**
    override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
        val view: View
        val holder: ViewHolder

        // 1. 视图复用:有回收的View就用,没有就创建新的(环保!)
        if (convertView == null) {
            // 第一次,初始化View和ViewHolder
            view = LayoutInflater.from(context).inflate(R.layout.grid_item, parent, false)
            holder = ViewHolder(view)
            view.tag = holder // 把ViewHolder“藏”在View里
        } else {
            // 第二次及以后,直接使用回收的View和里面的ViewHolder
            view = convertView
            holder = view.tag as ViewHolder
        }

        // 2. 绑定数据:把当前位置的数据设置到ViewHolder的视图上
        val imageResId = imageResIds[position]
        holder.imageView.setImageResource(imageResId)
        holder.textView.text = "Item $position"

        return view
    }

    // ViewHolder模式,避免每次都findViewById,提升滑动的流畅度!
    private class ViewHolder(view: View) {
        val imageView: ImageView = view.findViewById(R.id.iv_image)
        val textView: TextView = view.findViewById(R.id.tv_title)
    }
}

敲黑板! 上面代码里的 ViewHolderconvertView 是性能优化的关键,能让你滑动列表时如丝般顺滑,一定要用上!

三、 让它“活”起来:处理Item的点击事件

一个不能点的GridView,就像一盘不能吃的菜,中看不中用。给它加上点击监听,so easy!

// 在Activity或Fragment中
gridView.onItemClickListener = AdapterView.OnItemClickListener { parent, view, position, id ->
    // position就是你点击的那个Item的位置
    val clickedImageResId = imageResIds[position]
    Toast.makeText(this, "你点击了第${position + 1}个格子", Toast.LENGTH_SHORT).show()

    // 这里可以跳转到详情页、放大图片等等,随你发挥!
}
四、 实战!打造一个“时尚单品”展示墙(完整示例)

理论说再多,不如代码跑一跑。我们来手把手撸一个商品展示网格。

1. 布局文件:activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="16dp"
    android:orientation="vertical">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="潮流单品合集"
        android:textSize="24sp"
        android:textStyle="bold"
        android:gravity="center"
        android:layout_marginBottom="16dp"/>

    <GridView
        android:id="@+id/gridView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:numColumns="auto_fit" <!-- 自动适配列数 -->
        android:columnWidth="160dp"   <!-- 每列宽度 -->
        android:verticalSpacing="16dp" <!-- 垂直间距 -->
        android:horizontalSpacing="16dp" <!-- 水平间距 -->
        android:stretchMode="spacingWidthUniform" <!-- 拉伸间距,保持格子大小 -->
        android:gravity="center" />

</LinearLayout>

2. 网格Item的布局:grid_item.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:background="@drawable/bg_grid_item" <!-- 加个圆角背景,更美观 -->
    android:padding="8dp">

    <ImageView
        android:id="@+id/iv_image"
        android:layout_width="match_parent"
        android:layout_height="120dp"
        android:scaleType="centerCrop"
        android:src="@drawable/placeholder" />

    <TextView
        android:id="@+id/tv_title"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="商品标题"
        android:textSize="14sp"
        android:textStyle="bold"
        android:padding="8dp"
        android:gravity="center"
        android:maxLines="1"
        android:ellipsize="end" />

    <Button
        android:id="@+id/btn_buy"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="立即购买"
        android:textSize="12sp"
        android:backgroundTint="@color/teal_700" />

</LinearLayout>

3. 主Activity:MainActivity.kt

class MainActivity : AppCompatActivity() {

    private lateinit var gridView: GridView

    // 模拟数据:图片资源ID和商品标题
    private val productList = listOf(
        Product(R.drawable.product1, "复古印花T恤"),
        Product(R.drawable.product2, "高腰直筒牛仔裤"),
        Product(R.drawable.product3, "设计师联名帆布鞋"),
        Product(R.drawable.product4, "极简风双肩包"),
        Product(R.drawable.product5, "潮流棒球帽"),
        Product(R.drawable.product6, "个性手机壳"),
        // ... 可以继续加更多
    )

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        gridView = findViewById(R.id.gridView)

        // 设置适配器,注入灵魂!
        val adapter = ProductAdapter(this, productList)
        gridView.adapter = adapter

        // 处理点击事件
        gridView.onItemClickListener = AdapterView.OnItemClickListener { parent, view, position, id ->
            val selectedProduct = productList[position]
            Toast.makeText(this, "你种草了:${selectedProduct.title}", Toast.LENGTH_SHORT).show()
            // 实际开发中,这里可以跳转到商品详情页
        }
    }
}

// 数据类,用来封装商品数据
data class Product(val imageResId: Int, val title: String)

// 适配器
class ProductAdapter(
    private val context: Context,
    private val productList: List<Product>
) : BaseAdapter() {

    override fun getCount(): Int = productList.size
    override fun getItem(position: Int): Any = productList[position]
    override fun getItemId(position: Int): Long = position.toLong()

    override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
        val view: View
        val holder: ViewHolder

        if (convertView == null) {
            view = LayoutInflater.from(context).inflate(R.layout.grid_item, parent, false)
            holder = ViewHolder(view)
            view.tag = holder
        } else {
            view = convertView
            holder = view.tag as ViewHolder
        }

        val product = productList[position]
        holder.imageView.setImageResource(product.imageResId)
        holder.textView.text = product.title

        // 甚至可以处理内部按钮的点击事件
        holder.buyButton.setOnClickListener {
            Toast.makeText(context, "恭喜你,成功下单【${product.title}】!", Toast.LENGTH_LONG).show()
        }

        return view
    }

    private class ViewHolder(view: View) {
        val imageView: ImageView = view.findViewById(R.id.iv_image)
        val textView: TextView = view.findViewById(R.id.tv_title)
        val buyButton: Button = view.findViewById(R.id.btn_buy)
    }
}

运行效果: 一个3列(根据屏幕宽度自动计算)的商品展示墙就诞生了!每个商品有图片、标题和购买按钮,点击格子有反馈,点击按钮还能直接购买,体验拉满!

结语:别犹豫,盘它!

好了,看到这里,你已经从GridView的“路人”晋级为可以跟它“称兄道弟”的熟人了。它不是什么高深莫测的黑科技,而是一个实用、高效、能立刻为你App颜值加分的工具。

记住那几个关键属性,用好Adapter和ViewHolder,处理好点击事件,你的应用界面就能告别“菜市场既视感”,瞬间拥有高级“橱窗感”。

还等什么?赶紧打开Android Studio,把上面的代码Copy过去跑起来,亲手打造你的第一个“格子衫”应用吧!遇到问题?别怕,那只是你和代码之间“增进感情”的小游戏。祝你编码愉快!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

值引力

持续创作,多谢支持!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值