用 RecyclerView 实现刻度尺或仪表盘功能

使用 RecyclerView 实现刻度尺(或标尺)的功能,自定义Item 和适配器来完成。具体实现步骤:

请添加图片描述

1. 定义RecyclerView Item 即 刻度尺的布局文件layout_item_scale.xml:

LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:gravity="bottom|center_horizontal">
    <TextView
        android:id="@+id/scale_value"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="10sp"
        android:gravity="center"
        android:textColor="#000000"
        android:layout_marginBottom="10dp"
        tools:ignore="SmallSp" />
    <View
        android:id="@+id/scale_line"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</LinearLayout>

2. 创建 RecyclerView 的适配器:

在这里插入图片描述

public class ScaleAdapter extends RecyclerView.Adapter<ScaleAdapter.ScaleViewHolder> {
    private final int itemCount;

    public ScaleAdapter(int itemCount) {
        this.itemCount = itemCount;
    }

    @NonNull
    @Override
    public ScaleViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_item_scale, parent, false);
        return new ScaleViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull ScaleViewHolder holder, int position) {
        holder.bind(position);
    }

    @Override
    public int getItemCount() {
        return itemCount;
    }

    public static class ScaleViewHolder extends RecyclerView.ViewHolder {
        private final View scaleLine;
        private final TextView scaleValue;
        private final float density;


        public ScaleViewHolder(@NonNull View itemView) {
            super(itemView);
            scaleLine = itemView.findViewById(R.id.scale_line);
            scaleValue = itemView.findViewById(R.id.scale_value);
            density = itemView.getResources().getDisplayMetrics().density;
        }

        public void bind(int position) {
        
            int longestTickHeight = (int) (33 * density);  // 最长刻度高度
            int mediumTickHeight = (int) (23 * density);   // 中长刻度高度
            int shortTickHeight = (int) (10 * density);    // 短刻度高度

            int space = (int) (10 * density);
            int oneSpace = (int) (1 * density);

            if (position % 10 == 0) {
                // 每10个刻度为一个长刻度,显示刻度值
                LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(2, longestTickHeight);
                scaleLine.setLayoutParams(params);
                scaleLine.setBackgroundColor(0xFFCDCDCD);
                scaleValue.setText(String.valueOf(position / 10 + 76));

            } else if (position % 5 == 0) {
                // 每5个刻度为一个中等刻度
                scaleLine.setLayoutParams(new LinearLayout.LayoutParams(2, mediumTickHeight));
                scaleLine.setBackgroundColor(0xFFCDCDCD);
                scaleValue.setText("");

            } else {
                // 其他为短刻度
                scaleLine.setLayoutParams(new LinearLayout.LayoutParams(2, shortTickHeight));
                scaleLine.setBackgroundColor(0xFFCDCDCD);
                scaleValue.setText("");
            }

            LinearLayout.LayoutParams params;
            if (position % 2 == 0) {
                params = new LinearLayout.LayoutParams(space * 2, LinearLayout.LayoutParams.WRAP_CONTENT);
            } else {
                params = new LinearLayout.LayoutParams(oneSpace, LinearLayout.LayoutParams.WRAP_CONTENT);
            }
            params.bottomMargin = space;
            scaleValue.setLayoutParams(params);
        }
    }
}

3. 刻度尺 item 分为两种宽度:

if (position % 2 == 0) { // 偶数设置 2个宽度 space * 2
params = new LinearLayout.LayoutParams(space * 2, LinearLayout.LayoutParams.WRAP_CONTENT);
} else { // 奇数设置 1个宽度,即刻度尺的粗细
params = new LinearLayout.LayoutParams(oneSpace, LinearLayout.LayoutParams.WRAP_CONTENT);
}

4. 在 Activity 或 Fragment 中设置 RecyclerView:

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView

class MainActivity : AppCompatActivity() {

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

        val recyclerView = findViewById<RecyclerView>(R.id.recyclerView)
        recyclerView.layoutManager = LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false)
        // 设置初始的左右内边距
        val leftRightPadding = recyclerView.width / 2
        recyclerView.setPadding(leftRightPadding, 0, leftRightPadding, 0)
        recyclerView.setClipToPadding(false)
        
         // 这里假设最大值为100
        val scaleAdapter = ScaleAdapter(100) 
        recyclerView.adapter = scaleAdapter
    }
}


5. 滚动刻度尺到指定为止:

    val position = (channel?:60) - 50
    recyclerView.post {
        recyclerView.scrollToPosition(position)
    }

6. 滚动监听,获取停止后的数据:

    // 添加 LinearSnapHelper
    val snapHelper = LinearSnapHelper()
    snapHelper?.attachToRecyclerView(recyclerView)

    // 滚动监听
    recyclerView.addOnScrollListener(object: RecyclerView.OnScrollListener() {
        override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
                // 停止动作
            if (RecyclerView.SCROLL_STATE_IDLE == newState) { 
                // 防止快速滚动处理
                if (System.currentTimeMillis() - tempTime < 200) {
                 	return
                }
                val centerView = snapHelper?.findSnapView(recyclerView.layoutManager)
                if (centerView != null) {
                     // 获取对应的刻度值
                    val index = recyclerView.layoutManager?.getPosition(centerView)
                }
                tempTime = System.currentTimeMillis()
            }
        }
    })

---- 欢迎留言和讨论:

  • 12
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值