IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 游戏开发 -> 自定义睡眠分段VIew -> 正文阅读

[游戏开发]自定义睡眠分段VIew

自定义view效果图
在这里插入图片描述

在这里插入图片描述

使用

   <HomeLinChartLayout
			android:id="@+id/lc_specific_sleep"
	       android:layout_width="match_parent"
          android:layout_height="100dp"
          android:layout_marginTop="60dp"
          android:layout_weight="1"
          android:orientation="vertical"
          android:padding="6dp" />
sleeps = [SleepData(sleepType=1, sleepTypeTime=62), SleepData(sleepType=2, sleepTypeTime=33), SleepData(sleepType=1, sleepTypeTime=154), SleepData(sleepType=2, sleepTypeTime=19), SleepData(sleepType=1, sleepTypeTime=102), SleepData(sleepType=2, sleepTypeTime=23), SleepData(sleepType=1, sleepTypeTime=71)] //不同睡眠类型的集合 0清醒 1浅睡 2深睡 
totalSleep.light.toFloat() = 389.0 //当前日期的睡眠时间
DateTools.date2Str(sleepLists[0].date //这个是入睡时间    	


    var chartList = mutableListOf<SleepLineChartData>()
      chartList.add(
                SleepLineChartData(
                    sleeps, totalSleep.light.toFloat()
                    , DateTools.date2Str(sleepLists[0].date, "yyyy-MM-dd HH:mm:ss")
                )
            )
  lc_specific_sleep.setData(
                chartList,
                UIUtils.getAndroiodScreenProperty(),
                HomeLinChartLayout.TIME_TYPE_WEEK
            )
 lc_specific_sleep.setView()
 


HomeLinChartLayout.kt
package com.oplayer.orunningplus.function.main.todaySpecific.linChart

import com.oplayer.orunningplus.view.LinChart.SleepLineChartData

import android.content.Context
import android.graphics.*
import android.text.TextUtils
import android.util.AttributeSet
import android.view.Gravity
import android.widget.LinearLayout

/**
 * @author bishiqiangan@yeah.net
 * 重写一个LinearLayout, 遍历添加LinChartView
 */
class HomeLinChartLayout : LinearLayout {
    /**
     * 列表的数据源
     */
    private var mData: MutableList<SleepLineChartData>? = null
    /**
     * 屏幕的宽
     */
    private var scrW = 0
    /**
     * 屏幕的高
     */
    private var scrH = 0
    /**
     * 时间类型
     */
    private var timeType = 0

    constructor(
        context: Context?,
        attrs: AttributeSet?,
        defStyleAttr: Int
    ) : super(context, attrs, defStyleAttr)

    constructor(context: Context?, attrs: AttributeSet?) : super(
        context,
        attrs
    )

    constructor(context: Context?) : super(context) {
        this.orientation = VERTICAL
        setView()
    }

    fun setView() {
        if (mData != null && mData!!.isNotEmpty()) {
            var textAreW = 20
            if (timeType == TIME_TYPE_WEEK) {
                var text_max_length = 10
                for (data in mData!!) { // 获取最长文字的个数
                    if (!TextUtils.isEmpty(data.sleepLatency)) {
                        if (text_max_length <= data.sleepLatency!!.length) {
                            text_max_length = data.sleepLatency.length
                        }
                    }
                }
                val wh = textWH
                // 文字区域的宽
                textAreW =
                    text_max_length * wh[0] + dip2px(context, 10f)
            }
            // 图形区域的宽
            val chartAreW: Int
            chartAreW =  scrW -200
            val layoutParams =
                LayoutParams(
                    scrW - dip2px(
                        context,
                        10f
                    ), dip2px(context, 32f), 1f
                )
            // 设置居中
            layoutParams.gravity = Gravity.CENTER
            // 遍历添加LinChartView
            for (i in mData!!.indices) {
                val sleepLineChartData = mData!![i]
                val chartView = HomeLinChartView(context)
                chartView.setData(chartAreW, sleepLineChartData, timeType, i)
                if (i == 0) {
                    if (timeType == TIME_TYPE_MONTH) {
                        val first =
                            LayoutParams(
                                scrW - dip2px(
                                    context,
                                    10f
                                ), dip2px(context, 40f), 1f
                            )
                        // 设置居中
                        first.gravity = Gravity.CENTER
                        this.addView(chartView, first)
                    } else {
                        this.addView(chartView, layoutParams)
                    }
                } else {
                    this.addView(chartView, layoutParams)
                }
            }
        }
    }
    /**
     * 获取单个字符的高和宽
     */
    private val textWH: IntArray
        private get() {
            val wh = IntArray(2)
            // 一个矩形
            val rect = Rect()
            val text = "M"
            val paint = Paint()
            // 设置文字大小
            paint.textSize = dip2px(context, 3f).toFloat()
            paint.getTextBounds(text, 0, text.length, rect)
            wh[0] = rect.width()
            wh[1] = rect.height()
            return wh
        }

    fun setData(
        d: MutableList<SleepLineChartData>?,
        scrw: Int,
        timeType: Int
    ) {
        mData = d
        scrW = scrw
        this.timeType = timeType
        //在添加view之前要把之前所有添加过的view都清除掉
        removeAllViews()
    }

    companion object {
        /**
         * 周
         */
        const val TIME_TYPE_WEEK = 0
        /**
         * 月
         */
        const val TIME_TYPE_MONTH = 1

        /**
         * 根据手机的分辨率从 dp 的单位 转成为 px(像素)
         */
        fun dip2px(context: Context, dpValue: Float): Int {
            val scale = context.resources.displayMetrics.density
            return (dpValue * scale + 0.5f).toInt()
        }

        /**
         * 根据手机的分辨率从 px(像素) 的单位 转成为 dp
         */
        fun px2dip(context: Context, pxValue: Float): Int {
            val scale = context.resources.displayMetrics.density
            return (pxValue / scale + 0.5f).toInt()
        }
    }
}

HomeLinChartView.kt

package com.oplayer.orunningplus.function.main.todaySpecific.linChart
import android.app.Service
import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.DashPathEffect
import android.graphics.Paint
import android.text.TextPaint
import android.text.TextUtils
import android.util.AttributeSet
import android.util.DisplayMetrics
import android.view.View
import android.view.WindowManager
import com.example.myapplication.R

import com.oplayer.orunningplus.view.LinChart.SleepLineChartData
import java.text.ParseException
import java.text.SimpleDateFormat
import java.util.*

class HomeLinChartView : View {
    private lateinit var mData: SleepLineChartData
    private var mChartH = 0f
    private var mChartBottom = 0f
    private var arcPaint: Paint? = null
    private var timeType = 0
    private var top1 = 0
    private val code = 80
    val y_title = arrayOf("22:00","00:00", "02:00", "05:00","08:00")
    var mChartH1 = 0f
    var mChartH2 = 0f
    var mChartH3 = 0f
    var mChartTop1 = 0f
    var mChartTop2 = 0f
    var mChartTop3 = 0f
    private var position = 0
    constructor(context: Context?) : super(context)
    constructor(context: Context?, attrs: AttributeSet?) : super(
        context,
        attrs
    )

    constructor(
        context: Context?,
        attrs: AttributeSet?,
        defStyleAttr: Int
    ) : super(context, attrs, defStyleAttr)
    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        //画睡眠时间轴
        drawTimeLine(canvas)
        //画睡眠虚线
        drawTextDate(canvas)
        //画图形
        drawLine(canvas)
    }
    fun getHour(date: Date?): Int {
        val c = Calendar.getInstance()
        c.time = date
        return c[Calendar.HOUR_OF_DAY]
    }
    private fun drawTimeLine(canvas: Canvas) {
        val timeLinePaint = Paint()
        //timeLinePaint.color = UIUtils.getColor(R.color.sleep_details_date) // 上方点颜色
        timeLinePaint.textSize = dip2px(context, 10f).toFloat()
        // 设置文字右对齐
        // timeLinePaint.textAlign = Paint.Align.CENTER
        var code2 = 50f
        var nuber = 0
        for (i in 0..4) {
            canvas.drawText(
                y_title[i],
                code2,
                263f,
                timeLinePaint!!
            )
            code2 +=  200f
        }
    }
    /**
     * 将字符串日期时间转换成java.util.Date类型 日期时间格式yyyy-MM-dd HH:mm:ss
     *
     * @param datetime
     * @return
     */
    private val datetimeFormat =
        SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
    fun parseDatetime(datetime: String?): Date {
        return datetimeFormat.parse(datetime)
    }

    private fun getEndTime(
        startTime: Long,
        subTime: Int
    ): String {
        val time = subTime * 60000 + startTime
        var date = Date(time)
        return SimpleDateFormat("HH:mm").format(date)
    }
    private fun drawTextDate(canvas: Canvas) {
        //画左边的数据时间
        var mPaint :Paint = Paint(Paint.ANTI_ALIAS_FLAG)
        mPaint.color = resources.getColor(R.color.cardview_dark_background)


        mPaint.strokeWidth = 0.1f
        mPaint.pathEffect = DashPathEffect(floatArrayOf(3f, 3f), 0f)
        val centerY = height / 20
        val centerY2 = height
        //    setLayerType(LAYER_TYPE_SOFTWARE, null)
        canvas.drawLine(0f+60f, centerY.toFloat()-13f, width.toFloat()-55f, centerY.toFloat()-13f, mPaint)
        canvas.drawLine(0f+60f, centerY2.toFloat()-37f, width.toFloat()-55f, centerY2.toFloat()-37f, mPaint)
    }
    fun timeDifference(startTime: String?, endTime: String?): Float {
        val simpleFormat =
            SimpleDateFormat("yyyy-MM-dd hh:mm:ss")
        var from: Long = 0
        var to: Long = 0
        try {
            from = simpleFormat.parse(startTime).time
            to = simpleFormat.parse(endTime).time
        } catch (e: ParseException) {
            e.printStackTrace()
        }
        return ((to - from) / (1000 * 60)).toFloat()
    }
    /**
     * 得到指定月的天数
     */
    public fun getMonthLastDay(year: Int, month: Int): Int {
        val a = Calendar.getInstance()
        a[Calendar.YEAR] = year
        a[Calendar.MONTH] = month - 1
        a[Calendar.DATE] = 1 //把日期设置为当月第一天
        //roll()函数处理,只会比相应的字段进行处理,不会智能的对其它字段也进行逻辑上的改变。但是add()函数会在逻辑上改变其它字段,使结果正确。
        a.roll(Calendar.DATE, -1) //日期回滚一天,也就是最后一天
        return a[Calendar.DATE]
    }
    /**
     * 获得某年某月某日的前一天
     *
     * @param year
     * @param month
     * @return yyyy-MM-dd
     */
    fun getPreDay(year: Int, month: Int, day: Int): String {
        var year = year
        var month = month
        var day = day
        if (day != 1) { // 判断是否为某月月初
            day--
        } else {
            if (month != 1) { // 如果不是1月的话,那么就是上月月末
                month--
                day = getMonthLastDay(year, month)
            } else { // 如果是1月的话,那么就是上年的12月31日
                year--
                month = 12
                day = 31
            }
        }
        return "$year-$month-$day"
    }
    //日期减一天格式化处理
    fun getSubtractDay(s: String): String? {
        val date = s.split("-").toTypedArray()
        val year = date[0].toInt()
        val month = date[1].toInt()
        val day = date[2].toInt()
        val s1: String = getPreDay(year, month, day)
        val date1 = s1.split("-").toTypedArray()
        var monthStr = date1[1]
        var dayStr = date1[2]
        if (monthStr.length == 1) {
            monthStr = "0$monthStr"
        }
        if (dayStr.length == 1) {
            dayStr = "0$dayStr"
        }
        return date1[0] + "-" + monthStr + "-" + dayStr
    }
    /**
     * 绘制图形
     *
     * @param canvas
     */
    private fun drawLine(canvas: Canvas) {
        val wm =
            UIUtils.getContext().getSystemService(Context.WINDOW_SERVICE) as WindowManager
        val dm = DisplayMetrics()
        wm.defaultDisplay.getMetrics(dm)
        val height = dm.heightPixels // 屏幕高度(像素)
        val sleepViewHeight = height / 3
        val yPoint = sleepViewHeight

        // 需要导入 classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.20"
        if(mData.sleepLatency!=null&& mData.sleepLatency?.split(" ")?.size!! >1){
            arcPaint = Paint()
            var left = code.toFloat()-20
            val endHour = Integer.valueOf(
                mData.sleepLatency!!.split(" ").toTypedArray()[1].split(":").toTypedArray()[0]
            )
            val date = mData.sleepLatency!!.split(" ").toTypedArray()[0]
            //计算时间差   以00:00为基准
            val value: Float = timeDifference(
                (if (endHour in 21..23) date else getSubtractDay(date)) + " 22:00:00",
                mData.sleepLatency)

            if (value > 0) { //600 是22点到8点的总时长 单位分钟
                val dataWidth = mChartH / 600
                left += value * dataWidth
            }
            val rightMax = mChartH / 600 * 5 * 120 + code
            var right: Float // 循环里面尽量不要创建变量,避免造成频繁的GC
            for (sleepData in mData.dataList!!) {
                when (sleepData.sleepType) {
                    SLEEP_TYPE_AWAKE-> {
                        arcPaint!!.color = UIUtils.getColor(
                            R.color.sleep_details_awake
                        )
                        mChartBottom= mChartH1
                        top1 = mChartTop1.toInt()
                    }
                    SLEEP_TYPE_LIGHT-> {
                        arcPaint!!.color = UIUtils.getColor(
                            R.color.sleep_details_light
                        )
                        mChartBottom= mChartH2
                        top1 = mChartTop2.toInt()
                    }
                    SLEEP_TYPE_DEEP-> {
                        arcPaint!!.color = UIUtils.getColor(
                            R.color.sleep_details_deep
                        )
                        mChartBottom= mChartH3
                        top1 = mChartTop3.toInt()
                    }
                }
                arcPaint!!.isAntiAlias = true // 去除锯齿
                //绘制矩形
                right = left + sleepData.sleepTypeTime  * (mChartH / 600)
                if (left > rightMax) {
                    break
                } else if (right > rightMax) {
                    canvas.drawRect(left, top1.toFloat(), rightMax, mChartBottom, arcPaint!!)
//                canvas.drawRoundRect(left, top1.toFloat(), rightMax, mChartH,50f,50f,arcPaint!!)
                    break
                }
                canvas.drawRect(left, top1.toFloat(), right, mChartBottom, arcPaint!!)

//
                left = right
            }
        }

    }
    /**
     * 设置数据
     *
     * @param chartW
     * @param data
     * @param timeType
     * @param position
     */
    fun setData(chartW: Int, data: SleepLineChartData, timeType: Int, position: Int) {
        mChartH = chartW.toFloat()
        mChartH1 = mChartH*0.0f
        mChartH2 = mChartH*0.14f
        mChartH3 = mChartH*0.21f
        mChartTop1= mChartH*0.05f
        mChartTop2= mChartH*0.05f
        mChartTop3= mChartH*0.14f
        mData = data
        this.timeType = timeType
        this.position = position
        this.postInvalidate()
    }

    companion object {
        const val SLEEP_TYPE_AWAKE = 0 //醒来时间
        const val SLEEP_TYPE_LIGHT = 1 //浅睡时间
        const val SLEEP_TYPE_DEEP = 2 //深睡时间
        /**
         * @return 返回指定笔和指定字符串的长度
         */
        fun getFontLength(paint: Paint, str: String?): Float {
            return paint.measureText(str)
        }

        /**
         * @return 返回指定笔的文字高度
         */
        fun getFontHeight(paint: Paint): Float {
            val fm = paint.fontMetrics
            return fm.descent - fm.ascent
        }

        /**
         * @return 返回指定笔离文字顶部的基准距离
         */
        fun getFontLeading(paint: Paint): Float {
            val fm = paint.fontMetrics
            return fm.leading - fm.ascent
        }

        /**
         * 根据手机的分辨率从 dp 的单位 转成为 px(像素)
         */
        fun dip2px(context: Context, dpValue: Float): Int {
            val scale = context.resources.displayMetrics.density
            return (dpValue * scale + 0.5f).toInt()
        }

    }
}

SleepData.kt

package com.oplayer.orunningplus.view.LinChart

data class SleepData(var sleepType:Int, var sleepTypeTime:Int)

SleepLineChartData.kt

package com.oplayer.orunningplus.view.LinChart
/**
 * @author bishiqiangan@yeah.net
 * 数据模型类
 */
class SleepLineChartData(
    //不同睡眠类型的集合
    val dataList: List<SleepData>?,
    // 当前日期的睡眠时间
    val sleepTime: Float,
    //入睡時間
    val sleepLatency: String?
)

另外一种样式
在这里插入图片描述

LinChartVie.kt

package com.oplayer.orunningplus.view.LinChart

import android.app.Service
import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.text.TextUtils
import android.util.AttributeSet
import android.view.View
import com.oplayer.orunningplus.R
import com.oplayer.orunningplus.function.themeColor.DataColorBean
import com.oplayer.orunningplus.manager.DataManager
import com.oplayer.orunningplus.utils.DateUtil
import com.oplayer.orunningplus.utils.PreferencesHelper
import com.oplayer.orunningplus.utils.Slog
import com.oplayer.orunningplus.utils.UIUtils

class LinChartView : View {
    private lateinit var mData: SleepLineChartData
    private var mChartH = 0f
    private var arcPaint: Paint? = null
    private var timeType = 0
    private var top1 = 0
    private val code = 80
    var themeColor : DataColorBean? = null
    private val weekStr = intArrayOf(
        R.string.reminders_repeat_sun,
        R.string.reminders_repeat_mon,
        R.string.reminders_repeat_tue,
        R.string.reminders_repeat_wed,
        R.string.reminders_repeat_thu,
        R.string.reminders_repeat_fri,
        R.string.reminders_repeat_sat
    )
    private var position = 0

    constructor(context: Context?) : super(context)
    constructor(context: Context?, attrs: AttributeSet?) : super(
        context,
        attrs
    )

    constructor(
        context: Context?,
        attrs: AttributeSet?,
        defStyleAttr: Int
    ) : super(context, attrs, defStyleAttr)
    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        //画睡眠时间轴
        drawTimeLine(canvas)
        if (timeType == LinChartLayout.TIME_TYPE_MONTH) {
            if (position == 0) {
                return
            }
        }
        Slog.d("onDraw  $mData")
        drawTextDate(canvas)

        if (!this::mData.isInitialized || mData.dataList==null) {
            return
        }

        top1 = if (timeType == LinChartLayout.TIME_TYPE_WEEK) { // 画文字
            drawText(canvas, mData.sleepTime)
            100
        } else {
            10
        }
        //画图形
        drawLine(canvas)
    }

    private fun drawTimeLine(canvas: Canvas) {
        val timeLinePaint = Paint()
        themeColor()
        if((themeColor?.globalTextColor) != null) {
            timeLinePaint.color = Color.parseColor(themeColor?.globalTextColor)
        }
        //timeLinePaint.color = UIUtils.getColor(R.color.sleep_details_date) // 上方点颜色
        timeLinePaint.textSize = dip2px(context, 10f).toFloat()
        // 设置文字右对齐
        timeLinePaint.textAlign = Paint.Align.RIGHT
        val i1 = mChartH / 600 * 120
        val cy = if (timeType == LinChartLayout.TIME_TYPE_MONTH) 50 else 60
        for (i in 0..5) {
            if (position == 0) {
                canvas.drawCircle(i1 * i + code, cy.toFloat(), 10f, timeLinePaint)
                if (i == 0) {
                    canvas.drawText("22 pm", i1 * i + 120, 30f, timeLinePaint)
                } else if (i == 5) {
                    canvas.drawText("8 am", i1 * i + 120, 30f, timeLinePaint)
                }
                canvas.drawLine(
                    i1 * i + code,
                    cy.toFloat(),
                    i1 * i + code,
                    height.toFloat(),
                    timeLinePaint
                )
            } else {
                canvas.drawLine(
                    i1 * i + code,
                    0f,
                    i1 * i + code,
                    height.toFloat(),
                    timeLinePaint
                )
            }
        }
    }


    private fun drawTextDate(canvas: Canvas) {
        val textPaint = Paint()
        //画左边的数据时间
        themeColor()
        if((themeColor?.globalTextColor) != null) {
            textPaint.color = Color.parseColor(themeColor?.globalTextColor)
        }
        //textPaint.color = UIUtils.getColor(R.color.sleep_details_date)
        textPaint.textSize = dip2px(
            context,
            if (timeType == LinChartLayout.TIME_TYPE_WEEK) 14f else 12.toFloat()
        ).toFloat()
        // 设置文字左对齐
        textPaint.textAlign = Paint.Align.RIGHT
        val tY: Float
        // 注意第二个参数,左对齐,文字是从右开始写的,那么  x 就是对齐处的X坐标
        if (timeType == LinChartLayout.TIME_TYPE_WEEK) {
            tY =
                (height - getFontHeight(textPaint)) / 2 + getFontLeading(
                    textPaint
                ) + 50
            canvas.drawText(UIUtils.getString(weekStr[position]).substring(0,1), 70f, tY, textPaint)
        } else {
            tY =
                (height - getFontHeight(textPaint)) / 2 + getFontLeading(
                    textPaint
                ) + 5
            if (!TextUtils.isEmpty(mData.sleepLatency)) {
                canvas.drawText(
                    mData.sleepLatency!!.split(" ").toTypedArray()[0].split("-").toTypedArray()[2],
                    70f,
                    tY,
                    textPaint
                )
            } else {
                if (position == 1 || position == 5 || position == 10 || position == 15 || position == 20 || position == 25) {
                    canvas.drawText(position.toString() + "", 70f, tY, textPaint)

                }
            }
        }
    }

    /**
     * 绘制图形
     *
     * @param canvas
     */
    private fun drawLine(canvas: Canvas) {
        if(mData.sleepLatency!=null&& mData.sleepLatency?.split(" ")?.size!! >1){
            arcPaint = Paint()
            var left = code.toFloat()
            val endHour = Integer.valueOf(
                mData.sleepLatency!!.split(" ").toTypedArray()[1].split(":").toTypedArray()[0]
            )
            val date = mData.sleepLatency!!.split(" ").toTypedArray()[0]
            //计算时间差   以00:00为基准
            val value: Float = DateUtil.timeDifference(
                (if (endHour in 21..23) date else DateUtil.getSubtractDay(date)) + " 22:00:00",
                mData.sleepLatency)

            if (value > 0) { //600 是22点到8点的总时长 单位分钟
                val dataWidth = mChartH / 600
                left += value * dataWidth
            }
            val rightMax = mChartH / 600 * 5 * 120 + code
            var right: Float // 循环里面尽量不要创建变量,避免造成频繁的GC
            for (sleepData in mData.dataList!!) {
                when (sleepData.sleepType) {
                    SLEEP_TYPE_AWAKE -> arcPaint!!.color = UIUtils.getColor(
                        R.color.sleep_details_awake
                    )
                    SLEEP_TYPE_LIGHT -> arcPaint!!.color = UIUtils.getColor(
                        R.color.sleep_details_light
                    )
                    SLEEP_TYPE_DEEP -> arcPaint!!.color = UIUtils.getColor(
                        R.color.sleep_details_deep
                    )
                }
                arcPaint!!.isAntiAlias = true // 去除锯齿
                //绘制矩形
                right = left + sleepData.sleepTypeTime  * (mChartH / 600)
                if (left > rightMax) {
                    break
                } else if (right > rightMax) {
                    canvas.drawRect(left, top1.toFloat(), rightMax, mChartH, arcPaint!!)
//                canvas.drawRoundRect(left, top1.toFloat(), rightMax, mChartH,50f,50f,arcPaint!!)
                    break
                }
                canvas.drawRect(left, top1.toFloat(), right, mChartH, arcPaint!!)
//            canvas.drawRoundRect(left, top1.toFloat(), right, mChartH,50f,50f, arcPaint!!)
                left = right
            }
        }
    }
    fun themeColor() {
        val sharedPreferences = UIUtils.getContext().getSharedPreferences("themeColor", Service.MODE_PRIVATE)
        var checkedThemeName= PreferencesHelper.isTheme()
        var themeName = sharedPreferences?.getString("themeName$checkedThemeName","")
        themeColor = DataManager.getThemeColor("$themeName")
    }
    /**
     * 绘制文字说明  右对齐
     *
     * @param canvas
     * @param sleepTime 睡眠時間
     */
    private fun drawText(canvas: Canvas, sleepTime: Float) {
        val x = width
        val y = height
        val sleepTimeStr = "${(sleepTime / 60).toInt()}:${(sleepTime % 60).toInt()}"
        val textPaint = Paint()
        //画右边周的数据时间
        themeColor()
        if((themeColor?.globalTextColor) != null) {
            textPaint.color = Color.parseColor(themeColor?.globalTextColor)
        }
        // textPaint.color = UIUtils.getColor(R.color.sleep_details_goal)
        textPaint.textSize = dip2px(context, 15f).toFloat()
        // 设置文字左对齐
        textPaint.textAlign = Paint.Align.LEFT
        val tX = x - getFontLength(textPaint, sleepTimeStr)-dip2px(context, 8f).toFloat()
        val tY = (y - getFontHeight(textPaint)) / 2 + getFontLeading(textPaint) + 50
        // 注意第二个参数,左对齐,文字是从右开始写的,那么  x 就是对齐处的X坐标
        canvas.drawText(sleepTimeStr, tX, tY, textPaint)
    }

    /**
     * 设置数据
     *
     * @param chartW
     * @param data
     * @param timeType
     * @param position
     */
    fun setData(chartW: Int, data: SleepLineChartData, timeType: Int, position: Int) {
        mChartH = chartW.toFloat()
        mData = data
        this.timeType = timeType
        this.position = position
        this.postInvalidate()
    }

    companion object {
        const val SLEEP_TYPE_AWAKE = 0 //醒来时间
        const val SLEEP_TYPE_LIGHT = 1 //浅睡时间
        const val SLEEP_TYPE_DEEP = 2 //深睡时间
        /**
         * @return 返回指定笔和指定字符串的长度
         */
        fun getFontLength(paint: Paint, str: String?): Float {
            return paint.measureText(str)
        }

        /**
         * @return 返回指定笔的文字高度
         */
        fun getFontHeight(paint: Paint): Float {
            val fm = paint.fontMetrics
            return fm.descent - fm.ascent
        }

        /**
         * @return 返回指定笔离文字顶部的基准距离
         */
        fun getFontLeading(paint: Paint): Float {
            val fm = paint.fontMetrics
            return fm.leading - fm.ascent
        }

        /**
         * 根据手机的分辨率从 dp 的单位 转成为 px(像素)
         */
        fun dip2px(context: Context, dpValue: Float): Int {
            val scale = context.resources.displayMetrics.density
            return (dpValue * scale + 0.5f).toInt()
        }

    }
}

LinChartLayout.kt

package com.oplayer.orunningplus.view.LinChart

import android.content.Context
import android.graphics.Color
import android.graphics.Paint
import android.graphics.Rect
import android.text.TextUtils
import android.util.AttributeSet
import android.view.Gravity
import android.widget.LinearLayout
import com.oplayer.orunningplus.utils.Slog
import java.util.*

/**
 * @author bishiqiangan@yeah.net
 * 重写一个LinearLayout, 遍历添加LinChartView
 */
class LinChartLayout : LinearLayout {
    /**
     * 列表的数据源
     */
    private var mData: MutableList<SleepLineChartData>? = null
    /**
     * 屏幕的宽
     */
    private var scrW = 0
    /**
     * 时间类型
     */
    private var timeType = 0

    constructor(
        context: Context?,
        attrs: AttributeSet?,
        defStyleAttr: Int
    ) : super(context, attrs, defStyleAttr)

    constructor(context: Context?, attrs: AttributeSet?) : super(
        context,
        attrs
    )

    constructor(context: Context?) : super(context) {
        this.orientation = VERTICAL
        setView()
    }

    fun setView() {
        if (mData != null && mData!!.isNotEmpty()) {
            var textAreW = 20
            if (timeType == TIME_TYPE_WEEK) {
                var text_max_length = 10
                for (data in mData!!) { // 获取最长文字的个数
                    if (!TextUtils.isEmpty(data.sleepLatency)) {
                        if (text_max_length <= data.sleepLatency!!.length) {
                            text_max_length = data.sleepLatency.length
                        }
                    }
                }
                val wh = textWH
                // 文字区域的宽
                textAreW =
                    text_max_length * wh[0] + dip2px(context, 10f)
            }
            // 图形区域的宽
            val chartAreW: Int
            chartAreW = if (textAreW == 20) { //月
                scrW - 200
            } else { //周
                scrW - textAreW - 60
            }
            val layoutParams =
                LayoutParams(
                    scrW - dip2px(
                        context,
                        10f
                    ), dip2px(context, 32f), 1f
                )
            // 设置居中
            layoutParams.gravity = Gravity.CENTER
            // 设置Margin
//            layoutParams.topMargin = dip2px(getContext(), 2);
//            layoutParams.bottomMargin = dip2px(getContext(), 2);
//            layoutParams.leftMargin = dip2px(getContext(), 2);
//            layoutParams.rightMargin = dip2px(getContext(), 2);
            if (mData!!.size > 7) {
                val mMothData: MutableList<SleepLineChartData> =
                    ArrayList()
                mMothData.add(SleepLineChartData(null, 0f, null))
                mMothData.addAll(mData!!)
                mData!!.clear()
                mData!!.addAll(mMothData)
            }
            // 遍历添加LinChartView
            for (i in mData!!.indices) {
                val sleepLineChartData = mData!![i]
                val chartView = LinChartView(context)
                chartView.setData(chartAreW, sleepLineChartData, timeType, i)
                if (i == 0) {
                    if (timeType == TIME_TYPE_MONTH) {
                        val first =
                            LayoutParams(
                                scrW - dip2px(
                                    context,
                                    10f
                                ), dip2px(context, 40f), 1f
                            )
                        // 设置居中
                        first.gravity = Gravity.CENTER
                        this.addView(chartView, first)
                    } else {
                        this.addView(chartView, layoutParams)
                    }
                } else {
                    this.addView(chartView, layoutParams)
                }
            }
        }
    }
    /**
     * 获取单个字符的高和宽
     */
    private val textWH: IntArray
        private get() {
            val wh = IntArray(2)
            // 一个矩形
            val rect = Rect()
            val text = "M"
            val paint = Paint()
            // 设置文字大小
            paint.textSize = dip2px(context, 3f).toFloat()
            paint.getTextBounds(text, 0, text.length, rect)
            wh[0] = rect.width()
            wh[1] = rect.height()
            return wh
        }

    fun setData(
        d: MutableList<SleepLineChartData>?,
        scrw: Int,
        timeType: Int
    ) {
        mData = d
        scrW = scrw
        this.timeType = timeType
        //在添加view之前要把之前所有添加过的view都清除掉
        removeAllViews()
    }

    companion object {
        /**
         * 周
         */
        const val TIME_TYPE_WEEK = 0
        /**
         * 月
         */
        const val TIME_TYPE_MONTH = 1

        /**
         * 根据手机的分辨率从 dp 的单位 转成为 px(像素)
         */
        fun dip2px(context: Context, dpValue: Float): Int {
            val scale = context.resources.displayMetrics.density
            return (dpValue * scale + 0.5f).toInt()
        }

        /**
         * 根据手机的分辨率从 px(像素) 的单位 转成为 dp
         */
        fun px2dip(context: Context, pxValue: Float): Int {
            val scale = context.resources.displayMetrics.density
            return (pxValue / scale + 0.5f).toInt()
        }
    }
}
  游戏开发 最新文章
6、英飞凌-AURIX-TC3XX: PWM实验之使用 GT
泛型自动装箱
CubeMax添加Rtthread操作系统 组件STM32F10
python多线程编程:如何优雅地关闭线程
数据类型隐式转换导致的阻塞
WebAPi实现多文件上传,并附带参数
from origin ‘null‘ has been blocked by
UE4 蓝图调用C++函数(附带项目工程)
Unity学习笔记(一)结构体的简单理解与应用
【Memory As a Programming Concept in C a
上一篇文章      下一篇文章      查看所有文章
加:2022-03-10 22:58:11  更:2022-03-10 22:58:28 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/27 14:40:16-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码