Android Gantt View 安卓实现项目甘特图

需要做一个项目管理工具,其中使用到了甘特图。发现全网甘特图解决方案比较少,于是自动动手丰衣足食。

前面我用 Python和 Node.js 前端都做过,这次仅仅是移植到 Android上面。

其实甘特图非常简单,开发也不难,如果我专职去做,能做出一个非常棒产品。我写这个只是消遣,玩玩,闲的蛋痛,所以不怎么上心,就搞成下面这德行吧。仅仅供大家学习,参考。

那天心情好了,完善一下。

屏幕布局文件

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"><ScrollViewandroid:layout_width="match_parent"android:layout_height="match_parent"></ScrollView><HorizontalScrollViewandroid:layout_width="match_parent"android:layout_height="match_parent"><cn.netkiller.gantt.ui.GanttViewandroid:layout_width="wrap_content"android:layout_height="match_parent"android:background="#DEDEDE"android:keepScreenOn="true"android:padding="15dp"android:text="TextView" /></HorizontalScrollView></androidx.constraintlayout.widget.ConstraintLayout>

View 代码

package cn.netkiller.gantt.ui;import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.drawable.Drawable;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;/*** TODO: document your custom view class.*/
public class GanttView extends View {private final String TAG = GanttView.class.getSimpleName();private Drawable mExampleDrawable;private int contentWidth, contentHeight;private int paddingLeft, paddingTop, paddingRight, paddingBottom;private int canvasLeft, canvasTop, canvasRight, canvasBottom;private Canvas canvas;private int textSize;private Map<Date, Coordinate> coordinates = new HashMap<Date, Coordinate>();public static class Coordinate {public int x, y;public Coordinate(int x, int y) {this.x = x;this.y = y;}public int getX() {return x;}public void setX(int x) {this.x = x;}public int getY() {return y;}public void setY(int y) {this.y = y;}@Overridepublic String toString() {return "Coordinate{" +"x=" + x +", y=" + y +'}';}}public GanttView(Context context) {super(context);init(null, 0);}public GanttView(Context context, AttributeSet attrs) {super(context, attrs);init(attrs, 0);}public GanttView(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);init(attrs, defStyle);}private void init(AttributeSet attrs, int defStyle) {paddingLeft = getPaddingLeft();paddingTop = getPaddingTop();paddingRight = getPaddingRight();paddingBottom = getPaddingBottom();contentWidth = getWidth() - paddingLeft - paddingRight;contentHeight = getHeight() - paddingTop - paddingBottom;// Load attributes
//        final TypedArray a = getContext().obtainStyledAttributes(
//                attrs, R.styleable.MyView, defStyle, 0);
//mExampleString = a.getString(R.styleable.MyView_exampleString);
//        mExampleString = "AAAA";
//        mExampleColor = a.getColor(
//                R.styleable.MyView_exampleColor,
//                mExampleColor);
//        // Use getDimensionPixelSize or getDimensionPixelOffset when dealing with
//        // values that should fall on pixel boundaries.
//        mExampleDimension = a.getDimension(
//                R.styleable.MyView_exampleDimension,
//                mExampleDimension);
//
//        if (a.hasValue(R.styleable.MyView_exampleDrawable)) {
//            mExampleDrawable = a.getDrawable(
//                    R.styleable.MyView_exampleDrawable);
//            mExampleDrawable.setCallback(this);
//        }
//
//        a.recycle();}//    @Override
//    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
//        super.onSizeChanged(w, h, oldw, oldh);
//if (h < computeVerticalScrollRange()) {canScroll = true;} else {canScroll = false;}
//    }public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);setMeasuredDimension(contentWidth, contentHeight);}
//
//    private boolean canScroll = true;
//
//    @Override
//    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
//        super.onSizeChanged(w, h, oldw, oldh);
//
//        if (h < computeVerticalScrollRange()) {
//            canScroll = true;
//        } else {
//            canScroll = false;
//        }
//    }List<Data> taskList = List.of(new Data("AAA", "2024-06-28", "2024-07-04", "1", "Neo"),new Data("AAABBB", "2024-06-15", "2024-06-20", "10", "Neo"),new Data("AAACC", "2024-06-25", "2024-06-27", "1", "Neo"),new Data("AAABBCCD", "2024-06-25", "2024-06-28", "1", "Neo"),new Data("消息推送", "2024-01-15", "2024-06-30", "1", "Neo"),new Data("AAA", "2024-06-05", "2024-07-12", "1", "Neo"),new Data("AAA", "2024-06-05", "2024-07-17", "1", "Neo"),new Data("AAA", "2024-06-15", "2024-07-07", "1", "Neo"),new Data("AAA", "2024-06-18", "2024-07-02", "1", "Neo"),new Data("AAA", "2024-06-05", "2024-07-05", "1", "Neo"));@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);this.canvas = canvas;canvasTop = paddingTop;canvasLeft = paddingLeft;canvasRight = canvas.getWidth() - paddingRight;canvasBottom = canvas.getHeight() - paddingBottom;Paint paint = new Paint();paint.setStyle(Paint.Style.STROKE);paint.setColor(Color.BLUE);paint.setStrokeWidth(2);canvas.drawRect(0, 0, getWidth(), getHeight(), paint);paint.setColor(Color.DKGRAY);paint.setStyle(Paint.Style.FILL_AND_STROKE);paint.setAlpha(30);canvas.drawRect(canvasLeft, canvasTop, canvasRight, canvasBottom, paint);title("canvas");try {calendar("2024-06-12", "2024-07-20");tasks(taskList);} catch (Exception e) {}// Draw the example drawable on top of the text.if (mExampleDrawable != null) {mExampleDrawable.setBounds(paddingLeft, paddingTop,paddingLeft + contentWidth, paddingTop + contentHeight);mExampleDrawable.draw(canvas);}}public Map<String, Float> colume(List<Data> taskList) {TextPaint textPaint = new TextPaint();textPaint.setTextSize(sp2px(20));float name = textPaint.measureText("任务");float start = textPaint.measureText("开始日期");float finish = textPaint.measureText("截止日期");float day = textPaint.measureText("工时");float resource = textPaint.measureText("资源");for (Data data : taskList) {float textWidth = textPaint.measureText(data.name);if (textWidth > name) {name = textWidth;}if (textPaint.measureText(data.start) > start) {start = textPaint.measureText(data.start);}if (textPaint.measureText(data.finish) > finish) {finish = textPaint.measureText(data.finish);}if (textPaint.measureText(data.day) > day) {day = textPaint.measureText(data.day);}if (textPaint.measureText(data.resource) > resource) {resource = textPaint.measureText(data.resource);}}float finalName = name;float finalStart = start;float finalResource = resource;float finalFinish = finish;float finalDay = day;return new LinkedHashMap<String, Float>() {{put("任务", finalName);put("开始日期", finalStart);put("截止日期", finalFinish);put("工时", finalDay);put("资源", finalResource);}};}private int titleHeight;public float sp2px(float spValue) {//fontScale (DisplayMetrics类中属性scaledDensity)final float fontScale = getResources().getDisplayMetrics().scaledDensity;return (spValue * fontScale + 0.5f);}private void title(String value) {// Draw the text.TextPaint textPaint = new TextPaint();textPaint.setFlags(Paint.ANTI_ALIAS_FLAG);textPaint.setTextAlign(Paint.Align.LEFT);textPaint.setTextSize(sp2px(25));float textWidth = textPaint.measureText(value);Paint.FontMetrics fontMetrics = textPaint.getFontMetrics();
//        float textHeight = fontMetrics.bottom;float textHeight = textPaint.getFontSpacing();canvas.drawText(value,canvasLeft + (getWidth() - textWidth) / 2,canvasTop + textHeight,textPaint);textPaint.setTextSize(sp2px(18));String copyright = "https://www.netkiller.cn - design by netkiller";textWidth = textPaint.measureText(copyright);textHeight += textPaint.getFontSpacing();canvas.drawText(copyright,getWidth() - textWidth - canvasLeft,canvasTop + textHeight,textPaint);titleHeight = (int) textHeight;}private void process(String string, int x, int y, int size) {TextPaint mTextPaint = new TextPaint();mTextPaint.setTextSize(sp2px(size));
//        mTextWidth = mTextPaint.measureText(string);
//        Paint.FontMetrics fontMetrics = mTextPaint.getFontMetrics();
//        mTextHeight = fontMetrics.bottom;}private int tableEnd = 0;//    private void table() {
//
//TextPaint textPaint = new TextPaint();
//        calendarTextPaint.setTextSize(sp2px(20));
//
//        Paint.FontMetrics fontMetrics = calendarTextPaint.getFontMetrics();
//        float fontSpacing = calendarTextPaint.getFontSpacing();mTextHeight = fontMetrics.bottom;
//        int textX = canvasLeft + (int) fontSpacing / 2;
//        int textY = canvasTop + (int) fontSpacing * 3 + titleHeight;
//
//        int startX = 0;
//        int startY = (int) (canvasTop + titleHeight + fontSpacing * 2);
//        int stopX = startX;
//        int stopY = canvasBottom;
//
//        for (String text : List.of("任务", "开始日期", "截止日期", "工时", "资源")) {
//            canvas.drawText(text, textX, textY, calendarTextPaint);
//            textX += (int) (calendarTextPaint.measureText(text) + fontSpacing);
//            startX = stopX = textX;
//            canvas.drawLine(startX - (fontSpacing / 2), startY, stopX - (fontSpacing / 2), stopY, calendarPaint);
//        }
//        tableEnd = (int) (startX - (int) fontSpacing - fontSpacing / 2);
//
//    }private void table() {//        TextPaint textPaint = new TextPaint();calendarTextPaint.setTextSize(sp2px(20));//        Paint.FontMetrics fontMetrics = calendarTextPaint.getFontMetrics();float fontSpacing = calendarTextPaint.getFontSpacing();
//        mTextHeight = fontMetrics.bottom;int tableLeft = canvasLeft;int tableTop = canvasTop + (int) fontSpacing * 2 + titleHeight;int tableRight = canvasRight;int tableBottom = canvasBottom;int textX = tableLeft;int textY = tableTop + calendarFontSpacing;int startX = tableLeft;int startY = tableTop;int stopX = startX;int stopY = tableBottom;for (Map.Entry<String, Float> entry : colume(taskList).entrySet()) {String text = entry.getKey();Float textWidth = entry.getValue();canvas.drawText(text, textX + (int) fontSpacing / 2, textY, calendarTextPaint);textX += (int) (textWidth + calendarFontSpacing);startX += (int) (textWidth + calendarFontSpacing);stopX = startX;canvas.drawLine(startX, startY, stopX, stopY, calendarPaint);}tableEnd = tableRight = (int) (startX - calendarFontSpacing / 2);}private void tasks(List<Data> taskList) throws ParseException {Paint paint = new Paint();paint.setStyle(Paint.Style.FILL);paint.setColor(Color.BLUE);paint.setStrokeWidth(2);//        TextPaint textPaint = new TextPaint();
//        calendarPaint.setColor(Color.DKGRAY);calendarPaint.setColor(Color.GRAY);calendarTextPaint.setTextSize(sp2px(20));int taskTop = calendarTop + calendarFontSpacing * 3;int taskLeft = canvasLeft;int taskRight = tableEnd;int taskBottom = canvasBottom;//        Paint.FontMetrics fontMetrics = calendarTextPaint.getFontMetrics();
//        float fontSpacing = calendarTextPaint.getFontSpacing();int textX = 0;int textY = taskTop + calendarFontSpacing;int startX = 0;int startY = taskTop;int stopX = startX;int stopY = taskTop + calendarFontSpacing;//        canvas.drawLine(startX, calendarTop + calendarFontSpacing * 1, calendarRight, calendarTop + calendarFontSpacing * 1, calendarPaint);
//        canvas.drawLine(startX, startY - calendarFontSpacing, startX, stopY, calendarTextPaint);Map<String, Float> col = colume(taskList);Log.d(TAG, col.toString());for (Data task : taskList) {textX = taskLeft + (int) calendarFontSpacing / 2;Iterator<Float> aa = col.values().iterator();for (String text : List.of(task.name, task.start, task.finish, task.day, task.resource)) {Float textWidth = aa.next();canvas.drawText(text, textX, textY, calendarTextPaint);textX += (int) (textWidth + calendarFontSpacing);startX = stopX = textX;}textY += (int) (calendarFontSpacing);try {Date startData = new SimpleDateFormat("yyyy-MM-dd").parse(task.start);Date finishData = new SimpleDateFormat("yyyy-MM-dd").parse(task.finish);Log.e(TAG, "Start: " + String.valueOf(startData) + " Finish: " + finishData);Coordinate startCoordinates = coordinates.get(startData);Coordinate finishCoordinates = coordinates.get(finishData);Log.e(TAG, "Start: " + startCoordinates.toString() + "Finish: " + finishCoordinates);canvas.drawRect(startCoordinates.x + 5, startY + 5, finishCoordinates.x + calendarFontSpacing - 5, stopY - 5, paint);} catch (Exception e) {}
//            canvas.drawText(task.name, textX, textY, calendarTextPaint);startY += (int) (calendarFontSpacing);canvas.drawLine(canvasLeft, startY, calendarRight, stopY, calendarPaint);stopY += (int) (calendarFontSpacing);}}private Paint calendarPaint = new Paint();private TextPaint calendarTextPaint = new TextPaint();private int calendarFontSpacing;private int calendarLeft, calendarTop, calendarRight, calendarBottom;private void calendar(String startDate, String endDate) throws ParseException {calendarPaint.setStyle(Paint.Style.STROKE);calendarPaint.setColor(Color.DKGRAY);calendarPaint.setStrokeWidth(2);
//        calendarPaint.setTextSize(sp2px(20));
//        paint.setAlpha(50);calendarTextPaint.setTextSize(sp2px(20));calendarFontSpacing = (int) calendarTextPaint.getFontSpacing();//
//        Paint paint = new Paint();
//        paint.setTypeface(Typeface.DEFAULT);
//        paint.setTextSize(getTextSize());
//        Paint.FontMetrics fontMetrics = paint.getFontMetrics();
//        float textHeight = fm.getAscent() + fm.getDescent();//        float calendarFontSpacing = fontMetrics.descent - fontMetrics.ascent;
//        float calendarFontSpacing = fontMetrics.bottom - fontMetrics.top;//        Paint.FontMetrics fontMetrics = calendarPaint.getFontMetrics();
//        float textHeight = fontMetrics.getAscent() + fontMetrics.getDescent();// 边框canvas.drawRect(canvasLeft, canvasTop + titleHeight, canvasRight, canvasBottom, calendarPaint);table();calendarLeft = canvasLeft + tableEnd;calendarTop = canvasTop + titleHeight;calendarRight = canvasRight;calendarBottom = canvasBottom;int textX = calendarLeft;int textY = calendarTop + (int) calendarFontSpacing * 2;int startX = calendarLeft;int startY = calendarTop + (int) calendarFontSpacing * 1;int stopX = 0;int stopY = calendarBottom;canvas.drawLine(startX, calendarTop + calendarFontSpacing * 1, calendarRight, calendarTop + calendarFontSpacing * 1, calendarPaint);canvas.drawLine(startX, startY - calendarFontSpacing, startX, stopY, calendarTextPaint);canvas.drawLine(canvasLeft, calendarTop + calendarFontSpacing * 2, calendarRight, calendarTop + calendarFontSpacing * 2, calendarPaint);canvas.drawLine(canvasLeft, calendarTop + calendarFontSpacing * 3, canvasRight, calendarTop + calendarFontSpacing * 3, calendarPaint);//        Paint paint = new Paint();calendarPaint.setStyle(Paint.Style.FILL);calendarPaint.setColor(Color.BLUE);calendarPaint.setStrokeWidth(2);startY = calendarTop + (int) calendarFontSpacing * 2;int measureWeek = (int) calendarTextPaint.measureText("六");int measureDay = (int) calendarTextPaint.measureText("30");int measureText = measureWeek > measureDay ? measureWeek : measureDay;List<String> weeks = List.of("日", "一", "二", "三", "四", "五", "六");Calendar calendar = Calendar.getInstance();SimpleDateFormat format = new SimpleDateFormat("yyyy-MM");Date d1 = new SimpleDateFormat("yyyy-MM-dd").parse(startDate);//定义起始日期Date d2 = new SimpleDateFormat("yyyy-MM-dd").parse(endDate);//定义结束日期calendar.setTime(d2);calendar.add(Calendar.DATE, 1);d2 = calendar.getTime();calendar.setTime(d1);//设置日期起始时间while (calendar.getTime().before(d2)) {//判断是否到结束日期String month = new SimpleDateFormat("yyyy-MM").format(calendar.getTime());String day = new SimpleDateFormat("d").format(calendar.getTime());coordinates.put(calendar.getTime(), new Coordinate(startX, startY));
//            if (dateRange.containsKey(month)) {
//                List<Date> tmp = dateRange.get(month);
//                tmp.add(calendar.getTime());
//            } else {
//                dateRange.put(month, List.of(calendar.getTime()));
//            }int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);String week = weeks.get(dayOfWeek - 1);if (Set.of("六", "日").contains(week)) {calendarPaint.setColor(Color.WHITE);} else {calendarPaint.setColor(Color.GRAY);}
//            Log.d(TAG, String.valueOf());
//            Log.d(TAG, String.valueOf());stopX = (int) (startX + measureText);canvas.drawRect(startX, startY, stopX, stopY, calendarPaint);canvas.drawText(week, textX, textY, calendarTextPaint);if (calendarTextPaint.measureText(day) < calendarTextPaint.measureText(week)) {canvas.drawText(day, textX + calendarTextPaint.measureText(day) / 2, textY + calendarFontSpacing, calendarTextPaint);} else {canvas.drawText(day, textX, textY + calendarFontSpacing, calendarTextPaint);}if (day.equals("1")) {canvas.drawText(month, textX, textY - calendarFontSpacing, calendarTextPaint);canvas.drawLine(startX, startY - calendarFontSpacing * 2, startX, stopY, calendarTextPaint);}if (week.equals("日")) {canvas.drawLine(stopX, startY - calendarFontSpacing, stopX, stopY, calendarTextPaint);}textX += measureText + 2;startX = textX;calendar.add(Calendar.DATE, 1);//进行当前日期月份加1}calendarPaint.setColor(Color.GRAY);canvas.drawLine(canvasLeft, calendarTop + calendarFontSpacing * 2, calendarRight, calendarTop + calendarFontSpacing * 2, calendarPaint);canvas.drawLine(canvasLeft, calendarTop + calendarFontSpacing * 3, canvasRight, calendarTop + calendarFontSpacing * 3, calendarPaint);calendarLeft = stopX;}public class Data {public Data(String name, String start, String finish, String day, String resource) {this.name = name;this.start = start;this.finish = finish;this.day = day;this.resource = resource;}public String name;public String start;public String finish;public String day;public String resource;}
//    public class Coordinate{
//
//    }public void setTextSize(int textSize) {this.textSize = textSize;}public int getTextSize() {return textSize;}/*** Gets the example dimension attribute value.** @return The example dimension attribute value.*/
//    public float getExampleDimension() {
//        return mExampleDimension;
//    }/*** Sets the view"s example dimension attribute value. In the example view, this dimension* is the font size.** @param exampleDimension The example dimension attribute value to use.*/
//    public void setExampleDimension(float exampleDimension) {
//        mExampleDimension = exampleDimension;
//        invalidateTextPaintAndMeasurements();
//    }/*** Gets the example drawable attribute value.** @return The example drawable attribute value.*/
//    public Drawable getExampleDrawable() {
//        return mExampleDrawable;
//    }/*** Sets the view"s example drawable attribute value. In the example view, this drawable is* drawn above the text.** @param exampleDrawable The example drawable attribute value to use.*/
//    public void setExampleDrawable(Drawable exampleDrawable) {
//        mExampleDrawable = exampleDrawable;
//    }private void week() {Paint paint = new Paint();paint.setStyle(Paint.Style.FILL);paint.setColor(Color.BLUE);paint.setStrokeWidth(2);//        Paint.FontMetrics fontMetrics = textPaint.getFontMetrics();
//        float fontSpacing = calendarTextPaint.getFontSpacing();int textX = calendarLeft;int textY = calendarTop + (int) calendarFontSpacing * 2;int startX = calendarLeft;int startY = calendarTop + (int) calendarFontSpacing * 2;int stopX = 0;int stopY = calendarBottom;int measureWeek = (int) calendarTextPaint.measureText("六");int measureDay = (int) calendarTextPaint.measureText("30");int measureText = measureWeek > measureDay ? measureWeek : measureDay;List<String> weeks = List.of("一", "二", "三", "四", "五", "六", "日");int w = 0;for (int i = 1; i <= 31; i++) {//            for (String week : List.of("一", "二", "三", "四", "五", "六", "日")) {String week = weeks.get(w);w++;if (w >= weeks.size()) {w = 0;}String day = String.valueOf(i);if (Set.of("六", "日").contains(week)) {paint.setColor(Color.WHITE);} else {paint.setColor(Color.GRAY);}
//            Log.d(TAG, String.valueOf());
//            Log.d(TAG, String.valueOf());stopX = (int) (startX + measureText);canvas.drawRect(startX, startY, stopX, stopY, paint);canvas.drawText(week, textX, textY, calendarTextPaint);if (calendarTextPaint.measureText(day) < calendarTextPaint.measureText(week)) {canvas.drawText(day, textX + calendarTextPaint.measureText(day) / 2, textY + calendarFontSpacing, calendarTextPaint);} else {canvas.drawText(day, textX, textY + calendarFontSpacing, calendarTextPaint);}
//                if (week.equals("一")) {
//                    canvas.drawLine(startX, startY - calendarFontSpacing, startX, stopY, calendarTextPaint);
//                }if (week.equals("日")) {canvas.drawLine(stopX, startY - calendarFontSpacing, stopX, stopY, calendarTextPaint);}textX += measureText + 2;startX = textX;
//            stopX = (int) (startX + fontSpacing);}calendarLeft = stopX;}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/375767.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Emacs有什么优点,用Emacs写程序真的比IDE更方便吗?

GPT-4o (OpenAI) Emacs 是一种强大的文本编辑器&#xff0c;自1970年代以来一直在计算机领域中使用。它的优势以及在编程方面的便捷性取决于特定用户的需求和使用习惯。以下是一些 Emacs 的主要优点及其与 IDE 的比较&#xff1a; 优点 1. 灵活性和可扩展性&#xff1a; -…

端到端拥塞控制的本质

昨天整理了一篇 bbr 的微分方程组建模(参见 bbr 建模)&#xff0c;算是 bbr 算法终极意义上的一个总结&#xff0c;最后也顺带了对 aimd 的描述&#xff0c;算是我最近比较满意的一篇分享了。那么接下来的问题&#xff0c;脱离出具体算法&#xff0c;上升到宏观层面&#xff0c…

【游戏客户端】大话slg玩法架构(三)建筑控件

【游戏客户端】大话slg玩法架构&#xff08;三&#xff09;建筑控件 大家好&#xff0c;我是Lampard家杰~~ 今天我们继续给大家分享SLG玩法的实现架构&#xff0c;关于SLG玩法的介绍可以参考这篇上一篇文章&#xff1a;【游戏客户端】制作率土之滨Like玩法 PS&#xff1a;和之前…

JVM学习(day1)

JVM 运行时数据区 线程共享&#xff1a;方法区、堆 线程独享&#xff08;与个体“同生共死”&#xff09;&#xff1a;虚拟机栈、本地方法栈、程序计数器 程序计数器 作用&#xff1a;记录下次要执行的代码行的行号 特点&#xff1a;为一个没有OOM&#xff08;内存溢出&a…

电压反馈型运算放大器的增益和带宽

简介 本教程旨在考察标定运算放大器的增益和带宽的常用方法。需要指出的是&#xff0c;本讨论适用于电压反馈(VFB)型运算放大器。 开环增益 与理想的运算放大器不同&#xff0c;实际的运算放大器增益是有限的。开环直流增益(通常表示为AVOL)指放大器在反馈环路未闭合时的增益…

Python爬虫技术从去哪儿网获取旅游数据,对攻略进行可视化分析,提供全面的旅游攻略和个性化的出行建议

背景 随着信息技术的快速发展和互联网的普及&#xff0c;旅游行业也迎来了数字化和智能化的变革。去哪儿网作为中国领先的在线旅游平台之一&#xff0c;提供了丰富的旅游产品和服务&#xff0c;涵盖了机票、酒店、旅游度假等各个方面。用户通过去哪儿网可以方便地查询、预订和…

Mac下flutter运行iOS模拟器

上篇flutter环境安装&#xff08;Macvscode&#xff09;已经将vscode和xcode等开发环境都搭建起来了&#xff0c;vscode新建工程还是比较方便的&#xff0c;那么&#xff0c;建立好了之后&#xff0c;我们怎么看效果呢&#xff1f; 1. vscode新建项目 通过 vscode的命令命板(…

经典电影的高清修复是怎么实现的?

老片修复&#xff0c;主要分两种。精修版和流水线版。精修版比如像《星球大战》那种。基本就是一个专业团队花几年时间&#xff0c;不干别的就盯着这一个项目死磕。细致程度差不多就是一帧一帧进行修复。那对于我们普通人来说&#xff0c;想要修复视频高清&#xff0c;这种精修…

七天.NET 8操作SQLite入门到实战 - 第二天 在 Windows 上配置 SQLite环境

前言 SQLite的一个重要的特性是零配置的、无需服务器&#xff0c;这意味着不需要复杂的安装或管理。它跟微软的Access差不多&#xff0c;只是一个.db格式的文件。但是与Access不同的是&#xff0c;它不需要安装任何软件&#xff0c;非常轻巧。 七天.NET 8操作SQLite入门到实战…

Java常用的API_02(正则表达式、爬虫)

Java正则表达式 七、正则表达式7.1 格式7.1.1 字符类注意字符类示例代码1例2 7.1.2 预定义字符预定义字符示例代码例2 7.1.3 区别总结 7.2 使用Pattern和Matcher类与直接使用String类的matches方法的区别。&#xff08;1&#xff09; 使用Pattern和Matcher类示例代码 &#xff…

传输层协议之UDP

1、端口号 我们在应用层创建的套接字&#xff0c;是需要通过bind()接口绑定我们的IP地址与端口号的&#xff0c;这是因为数据从传输层向上交付到应用层时&#xff0c;需要用端口号来查找特定的服务进程。一般在网络通信时&#xff0c;用IP地址标识一台主机&#xff0c;用端口号…

el-table 动态添加删除 -- 鼠标移入移出显隐删除图标

<el-table class"list-box" :data"replaceDataList" border><el-table-column label"原始值" prop"original" align"center" ><template slot-scope"scope"><div mouseenter"showClick…

Kubelet 认证

当我们执行kubectl exec -it pod [podName] sh命令时&#xff0c;apiserver会向kubelet发起API请求。也就是说&#xff0c;kubelet会提供HTTP服务&#xff0c;而为了安全&#xff0c;kubelet必须提供HTTPS服务&#xff0c;且还要提供一定的认证与授权机制&#xff0c;防止任何知…

Bertopic环境安装与文本主题聚类

文章目录 1.环境配置(一)安装:anaconda1. 理解:为什么需要anaconda2. 下载anaconda3. 启动anaconda(二)安装:python环境(三)安装:依赖包hdbscan的安装问题解决方案1. 安装build-tools-for-visual-studio2. 安装hdbscan(四)安装transformers、BERTopic等重要依赖包2…

FlinkModule加载HiveModule异常

HiveModule这个模块加载不出来 加在不出来这个模块&#xff0c;网上查说是要加下面这个依赖 <dependency><groupId>org.apache.flink</groupId><artifactId>flink-connector-hive_${scala.binary.version}</artifactId><version>${flink.…

GPIO通用输入输出口

可配置八种输入输出模式&#xff1b; 引脚电平&#xff1a;0~3.3V&#xff0c;部分引脚可容忍5V&#xff1b;&#xff08;可以输入5V&#xff0c;输出最大只能是3.3V&#xff09; 带FT的是可以容忍5V的不带FT的就只能接入3.3V的电压。 输出模式下可以控制端口输出高低电平&am…

【算法】代码随想录之链表(更新中)

文章目录 前言 一、移除链表元素&#xff08;LeetCode--203&#xff09; 前言 跟随代码随想录&#xff0c;学习链表相关的算法题目&#xff0c;记录学习过程中的tips。 一、移除链表元素&#xff08;LeetCode--203&#xff09; 【1】题目描述&#xff1a; 【2】解决思想&am…

自动驾驶中,实现三维点旋转原理

文章目录 1. 三维点旋转的方案2. 使用复数表示二维点的旋转2.1. 复数的概念2.2. 复数的三种形式及相互转换2.3. 复数概念扩展&#xff1a;实数、虚数、复数 3. 四元数旋转三维点原理4. 使用四元数进行旋转的公式5. 旋转叠加6. 四元数转换为三维点7. 代码实现 1. 三维点旋转的方…

13 协程设计原理与汇编实现

协程的问题 为什么要有协程?协程的原语操作?协程的切换?协程的struct如何定义?协程的scheduler(调度)如何定义?调度策略如何实现?协程如何与posix,api兼容?协程多核模式?协程的性能如何测试?为什么要有协程 同步的编程方式,异步的性能。同步编程时,我们需要等待io就…

14-47 剑和诗人21 - 2024年如何打造AI创业公司

​​​​​ 2024 年&#xff0c;随着人工智能继续快速发展并融入几乎所有行业&#xff0c;创建一家人工智能初创公司将带来巨大的机遇。然而&#xff0c;在吸引资金、招聘人才、开发专有技术以及将产品推向市场方面&#xff0c;人工智能初创公司也面临着相当大的挑战。 让我来…