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

Android实现带垂直连线的公交站点追踪自定义ListView布局

实现带状态圆圈和垂直线的公交站点ListView布局

看起来你需要的是一个左侧带贯穿式垂直线、且垂直线穿过状态圆圈中心的列表项布局,同时根据站点途经状态切换圆圈颜色。我帮你调整布局和Adapter代码,来实现这个效果:


1. 修改列表项布局文件(listBusStops.xml)

首先调整布局,添加垂直线View,并确保它与圆圈中心对齐,同时让圆圈覆盖在线上(保证视觉上线穿过圆圈中心):

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

    <!-- 垂直线:位于圆圈中心,宽度2dp -->
    <View
        android:id="@+id/vertical_line"
        android:layout_width="2dp"
        android:layout_height="match_parent"
        android:layout_marginStart="14dp" <!-- 计算方式:圆圈中心(15dp) - 线宽一半(1dp) = 14dp -->
        android:background="@color/gray" />

    <!-- 状态圆圈:覆盖在线上,中心与线对齐 -->
    <ImageView
        android:id="@+id/ivstatus"
        android:layout_width="30dp"
        android:layout_height="30dp" />

    <!-- 站点名称:在圆圈右侧,垂直居中 -->
    <TextView
        android:id="@+id/tvname"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignTop="@id/ivstatus"
        android:layout_alignBottom="@id/ivstatus"
        android:layout_toEndOf="@id/ivstatus"
        android:layout_marginStart="12dp"
        android:gravity="center_vertical" />

</RelativeLayout>

2. 优化Custom_list Adapter代码

接下来调整Adapter,动态控制垂直线的显示范围(第一个项只显示下半段线,最后一个项只显示上半段线,中间项显示完整线),同时优化代码结构降低耦合:

import android.app.Activity;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import androidx.core.content.ContextCompat;
import java.util.ArrayList;

class Custom_list extends ArrayAdapter<String> {
    private final Activity context;
    private final ArrayList<String> stopNames;
    private final ArrayList<String> statusList;
    private final int greenCircleRes;
    private final int redCircleRes;
    private final int circleHalfHeight;

    public Custom_list(Activity context, ArrayList<String> stopNames, ArrayList<String> statusList) {
        super(context, R.layout.list_bus_stops, stopNames);
        this.context = context;
        this.stopNames = stopNames;
        this.statusList = statusList;
        this.greenCircleRes = R.drawable.circle_green;
        this.redCircleRes = R.drawable.circle_red;
        // 获取圆圈高度的一半(30dp的一半是15dp)
        this.circleHalfHeight = context.getResources().getDimensionPixelSize(R.dimen.circle_half_height);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        // 复用convertView提升性能
        View rowView = convertView;
        if (rowView == null) {
            LayoutInflater inflater = context.getLayoutInflater();
            rowView = inflater.inflate(R.layout.list_bus_stops, parent, false);
        }

        // 获取控件实例
        TextView tvName = rowView.findViewById(R.id.tvname);
        ImageView ivStatus = rowView.findViewById(R.id.ivstatus);
        View verticalLine = rowView.findViewById(R.id.vertical_line);

        // 设置站点名称
        tvName.setText(stopNames.get(position));

        // 设置圆圈颜色
        if (statusList.get(position).equalsIgnoreCase("yes")) {
            ivStatus.setImageResource(greenCircleRes);
        } else {
            ivStatus.setImageResource(redCircleRes);
        }

        // 动态调整垂直线的显示范围
        RelativeLayout.LayoutParams lineParams = (RelativeLayout.LayoutParams) verticalLine.getLayoutParams();
        if (position == 0) {
            // 第一个项:线从圆圈中心开始向下延伸
            lineParams.topMargin = circleHalfHeight;
            lineParams.bottomMargin = 0;
        } else if (position == stopNames.size() - 1) {
            // 最后一个项:线从顶部延伸到圆圈中心
            lineParams.topMargin = 0;
            lineParams.bottomMargin = circleHalfHeight;
        } else {
            // 中间项:线贯穿整个项的高度
            lineParams.topMargin = 0;
            lineParams.bottomMargin = 0;
        }
        verticalLine.setLayoutParams(lineParams);

        // 可选:根据前后站点状态设置线的颜色(已途经区间用绿色,未途经用灰色)
        if (position > 0) {
            boolean prevVisited = statusList.get(position - 1).equalsIgnoreCase("yes");
            boolean currentVisited = statusList.get(position).equalsIgnoreCase("yes");
            if (prevVisited && currentVisited) {
                verticalLine.setBackgroundColor(ContextCompat.getColor(context, R.color.green));
            } else {
                verticalLine.setBackgroundColor(ContextCompat.getColor(context, R.color.gray));
            }
        } else {
            // 第一个项的线默认灰色
            verticalLine.setBackgroundColor(ContextCompat.getColor(context, R.color.gray));
        }

        return rowView;
    }
}

3. 添加辅助资源

在res/values/dimens.xml中添加圆圈半高的定义:

<dimen name="circle_half_height">15dp</dimen>

在res/values/colors.xml中添加需要的颜色:

<color name="gray">#808080</color>
<color name="green">#4CAF50</color>

关键说明

  • 垂直线对齐:通过计算layout_marginStart让垂直线正好处于圆圈的中心位置,同时让圆圈覆盖在线上,实现"线穿过圆圈中心"的视觉效果。
  • 连贯线效果:通过动态设置垂直线的上下margin,让整条线在列表中连贯,不会在第一个/最后一个项出现多余的延伸。
  • 可选优化:添加了根据前后站点状态切换线颜色的逻辑,让已途经的区间线显示绿色,更符合公交追踪的业务逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 04:23:08