开源 java android app 开发(十三)自定义绘图控件--游戏摇杆

OSDU(Open Subsurface Data Universe,开放地下数据空间 / 开源地下数据生态系统) OSDU是由油气行业与云厂商共建的开源、云原生数据平台规范,旨在解决勘探开发领域数据孤岛、格式不统一、应用绑定等问题。其核心是“数据与应用解耦”,通过统一元数据模型、API及权限体系,实现跨云、跨项目的数据互通。平台支持地震、井筒、储层等专业数据管理,配套OpenVDS、ETP等标准,适配PB级体数据,支撑AI训练与数字孪生。虽为参考实现,非即用系统,但已成国际油气数字化底座趋势,国内三桶油正推进试点与国产化适配。 阅读详情

 文章的目的为了记录使用java 进行android app 开发学习的经历。本职为嵌入式软件开发,公司安排开发app,临时学习,完成app的开发。开发流程和要点有些记忆模糊,赶紧记录,防止忘记。

    相关链接:

开源 java android app 开发(一)开发环境的搭建-优快云博客

开源 java android app 开发(二)工程文件结构-优快云博客

开源 java android app 开发(三)GUI界面布局和常用组件-优快云博客

开源 java android app 开发(四)GUI界面重要组件-优快云博客

开源 java android app 开发(五)文件和数据库存储-优快云博客

开源 java android app 开发(六)多媒体使用-优快云博客

开源 java android app 开发(七)通讯之Tcp和Http-优快云博客

开源 java android app 开发(八)通讯之Mqtt和Ble-优快云博客

开源 java android app 开发(九)后台之线程和服务-优快云博客

开源 java android app 开发(十)广播机制-优快云博客

开源 java android app 开发(十一)调试、发布-优快云博客

开源 java android app 开发(十二)封库.aar-优快云博客

开源 java android app 开发(十三)自定义绘图控件--游戏摇杆

开源 java android app 开发(十四)自定义绘图控件--波形图

开源 java android app 开发(十五)自定义绘图控件--仪表盘

开源 java android app 开发(十六)自定义绘图控件--圆环

推荐链接:

开源C# .net mvc 开发(一)WEB搭建_c#部署web程序-优快云博客

开源 C# .net mvc 开发(二)网站快速搭建_c#网站开发-优快云博客

开源 C# .net mvc 开发(三)WEB内外网访问(VS发布、IIS配置网站、花生壳外网穿刺访问)_c# mvc 域名下不可訪問內網,內網下可以訪問域名-优快云博客

开源 C# .net mvc 开发(四)工程结构、页面提交以及显示_c#工程结构-优快云博客

开源 C# .net mvc 开发(五)常用代码快速开发_c# mvc开发-优快云博客

本章节主要内容是如何进行绘图并自定义控件。在Android开发中,经常需要自定义控件来实现特殊功能,本章主要讲如何自定义一个摇杆控件,通过拖动中间的圆圈,实现上下左右位置的输出,可以用到机器人或无人机的控制中。

1.绘图基础

2.摇杆控件的制作

3.效果图

一、绘图

在Android中使用Java进行绘图主要涉及以下几个核心类和概念:

1.1  Canvas类是Android绘图的基础,提供了各种绘制方法,以下为代码

public class CustomView extends View {
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        
        // 设置画笔
        Paint paint = new Paint();
        paint.setColor(Color.RED);
        paint.setStyle(Paint.Style.FILL);
        paint.setStrokeWidth(5);
        
        // 绘制矩形
        canvas.drawRect(100, 100, 300, 300, paint);
        
        // 绘制圆形
        paint.setColor(Color.BLUE);
        canvas.drawCircle(200, 200, 50, paint);
        
        // 绘制文本
        paint.setColor(Color.BLACK);
        paint.setTextSize(40);
        canvas.drawText("Hello Android", 50, 50, paint);
    }
}

1.2  Paint类控制绘图的样式和颜色,以下为代码
 

Paint paint = new Paint();
paint.setColor(Color.GREEN);          // 设置颜色
paint.setStyle(Paint.Style.STROKE);   // 设置填充样式(STROKE, FILL, FILL_AND_STROKE)
paint.setStrokeWidth(10);             // 设置线条宽度
paint.setAntiAlias(true);             // 开启抗锯齿
paint.setTextSize(30);                // 设置文本大小

1.3  绘制基本图形,以下为具体代码

// 绘制直线
canvas.drawLine(startX, startY, endX, endY, paint);

// 绘制矩形
canvas.drawRect(left, top, right, bottom, paint);

// 绘制圆角矩形
canvas.drawRoundRect(left, top, right, bottom, rx, ry, paint);

// 绘制圆形
canvas.drawCircle(centerX, centerY, radius, paint);

// 绘制椭圆
canvas.drawOval(left, top, right, bottom, paint);

// 绘制弧形
canvas.drawArc(left, top, right, bottom, startAngle, sweepAngle, useCenter, paint);

// 绘制路径
Path path = new Path();
path.moveTo(x1, y1);
path.lineTo(x2, y2);
path.quadTo(controlX, controlY, endX, endY);
canvas.drawPath(path, paint);

1.4  创建自定义View,自定义控件可以直接继承自View,以下为典型代码
 

public class MyCustomView extends View {
    private Paint paint;
    private Path path;

    public MyCustomView(Context context) {
        super(context);
        init();
    }

    public MyCustomView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    private void init() {
        paint = new Paint();
        paint.setColor(Color.BLUE);
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(5);
        paint.setAntiAlias(true);
        
        path = new Path();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawPath(path, paint);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        float x = event.getX();
        float y = event.getY();
        
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                path.moveTo(x, y);
                return true;
            case MotionEvent.ACTION_MOVE:
                path.lineTo(x, y);
                break;
            default:
                return false;
        }
        
        // 重绘视图
        invalidate();
        return true;
    }
}

二、遥杆控件的制作,在app开发中经常需要使用到摇杆控件,比如机器人控制,比如无人机的控制,以下为摇杆控件的具体制作方法。

2.1  创建基础类继承自view,JoystickView.java。主要实现摇杆控件的绘制和事件定义,摇杆通常外围会有底座,中间会有小圆圈代表摇杆,中间用三角形来代表方向。拉动时触发事件,提供回调接口供调用者使用。

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PointF;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

public class JoystickView extends View {


    // 绘制参数
    private Paint basePaint;        // 底座画笔
    private Paint outerRingPaint;   // 外圈浅灰色圆环
    private Paint middleRingPaint;  // 中间白色圆环
    private Paint trianglePaint;    // 三角形画笔
    private PointF centerPoint;     // 中心点
    private PointF stickPoint;      // 摇杆当前位置
    private float baseRadius;       // 底座半径
    private float stickRadius;      // 摇杆半径
    private float maxDistance;      // 最大移动距离
    private Path upTriangle;        // 上三角形路径
    private Path downTriangle;      // 下三角形路径
    private Bitmap stickBitmap;     // 摇杆图片

    private int stickImageResId = R.drawable.arr_fb; // 默认图片资源ID

    // 回调接口
    public interface OnJoystickMoveListener {
        void onValueChanged(float xPercent, float yPercent);
        void onReleased();
    }
    private OnJoystickMoveListener listener;

    // 构造方法


    public JoystickView(Context context) {
        super(context);
        init(null);
    }

    public JoystickView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(attrs);
    }

    public JoystickView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(attrs);
    }

    private void init(AttributeSet attrs) {

// 从XML属性获取自定义属性
        if (attrs != null) {
            TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.JoystickView);
            stickImageResId = a.getResourceId(R.styleable.JoystickView_stickImage, R.drawable.arr_fb);
            a.recycle();
        }

        // 初始化底座画笔(主灰色)
        basePaint = new Paint();
        //basePaint.setColor(Color.rgb(150, 150, 150));
        basePaint.setColor(Color.rgb(47, 47, 47));
        basePaint.setStyle(Paint.Style.FILL);
        basePaint.setAntiAlias(true);

        // 初始化外圈浅灰色圆环(宽度2)
        outerRingPaint = new Paint();
        outerRingPaint.setColor(Color.rgb(200, 200, 200));
        outerRingPaint.setStyle(Paint.Style.STROKE);
        outerRingPaint.setStrokeWidth(6f);
        outerRingPaint.setAntiAlias(true);

        // 初始化中间白色圆环(宽度3)
        middleRingPaint = new Paint();
        middleRingPaint.setColor(Color.WHITE);
        middleRingPaint.setStyle(Paint.Style.STROKE);
        middleRingPaint.setStrokeWidth(9f);
        middleRingPaint.setAntiAlias(true);


        // 初始化三角形画笔(白色)
        trianglePaint = new Paint();
        trianglePaint.setColor(Color.WHITE);
        trianglePaint.setStyle(Paint.Style.FILL);
        trianglePaint.setAntiAlias(true);


        //stickBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.arr_fb);
        if (stickBitmap != null && !stickBitmap.isRecycled()) {
            stickBitmap.recycle();
        }
        stickBitmap = BitmapFactory.decodeResource(getResources(), stickImageResId);

        centerPoint = new PointF();
        stickPoint = new PointF();
        upTriangle = new Path();
        downTriangle = new Path();


    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);

        // 计算中心点
        centerPoint.set(w / 2f, h / 2f);
        stickPoint.set(centerPoint);

        // 计算半径
        baseRadius = Math.min(w, h) * 0.4f;
        stickRadius = baseRadius * 0.3f;
        maxDistance = baseRadius - stickRadius - 20;

        // 如果图片太大,可以缩放
        if (stickBitmap != null) {
            int desiredSize = (int)(stickRadius * 2);
            stickBitmap = Bitmap.createScaledBitmap(stickBitmap, desiredSize, desiredSize, true);
        }

        // 初始化三角形路径
        updateTrianglePaths();
    }

    private void updateTrianglePaths() {
        /*
        float triangleHeight = stickRadius * 0.4f; // 三角形高度
        float triangleBase = (float) (2 * triangleHeight / Math.tan(Math.toRadians(30))); // 计算底边长度(120度角)
        float triangleSpacing = stickRadius * 0.4f; // 三角形间距

        // 上三角形(向上120度)
        upTriangle.reset();
        upTriangle.moveTo(stickPoint.x, stickPoint.y - triangleSpacing - triangleHeight);
        upTriangle.lineTo(stickPoint.x - triangleBase/2, stickPoint.y - triangleSpacing);
        upTriangle.lineTo(stickPoint.x + triangleBase/2, stickPoint.y - triangleSpacing);
        upTriangle.close();

        // 下三角形(向下120度)
        downTriangle.reset();
        downTriangle.moveTo(stickPoint.x, stickPoint.y + triangleSpacing + triangleHeight);
        downTriangle.lineTo(stickPoint.x - triangleBase/2, stickPoint.y + triangleSpacing);
        downTriangle.lineTo(stickPoint.x + triangleBase/2, stickPoint.y + triangleSpacing);
        downTriangle.close();
        */

    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        // 1. 绘制底座主圆
        canvas.drawCircle(centerPoint.x, centerPoint.y, baseRadius, basePaint);

        // 2. 绘制外圈浅灰色圆环(最外层)
        canvas.drawCircle(centerPoint.x, centerPoint.y, baseRadius - 3f, outerRingPaint);

        // 3. 绘制中间白色圆环
        canvas.drawCircle(centerPoint.x, centerPoint.y, baseRadius - 9f, middleRingPaint);

        // 4. 绘制摇杆图片(替换原来的圆圈)
        if (stickBitmap != null) {
            canvas.drawBitmap(stickBitmap,
                    stickPoint.x - stickBitmap.getWidth()/2,
                    stickPoint.y - stickBitmap.getHeight()/2,
                    null);
        } else {
            // 如果图片加载失败,绘制默认圆圈
            Paint stickPaint = new Paint();
            stickPaint.setColor(Color.rgb(220, 220, 220));
            stickPaint.setStyle(Paint.Style.FILL);
            stickPaint.setAntiAlias(true);
            canvas.drawCircle(stickPoint.x, stickPoint.y, stickRadius, stickPaint);
        }

        // 5. 绘制三角形(白色)
        canvas.drawPath(upTriangle, trianglePaint);
        canvas.drawPath(downTriangle, trianglePaint);
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        // 回收Bitmap资源
        if (stickBitmap != null && !stickBitmap.isRecycled()) {
            stickBitmap.recycle();
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        float touchX = event.getX();
        float touchY = event.getY();

        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
            case MotionEvent.ACTION_MOVE:
                float dx = touchX - centerPoint.x;
                float dy = touchY - centerPoint.y;
                float distance = (float) Math.sqrt(dx * dx + dy * dy);

                if (distance <= maxDistance) {
                    stickPoint.set(touchX, touchY);
                } else {
                    float ratio = maxDistance / distance;
                    stickPoint.set(
                            centerPoint.x + dx * ratio,
                            centerPoint.y + dy * ratio
                    );
                }

                updateTrianglePaths();

                float xPercent = (stickPoint.x - centerPoint.x) / maxDistance;
                float yPercent = (stickPoint.y - centerPoint.y) / maxDistance;

                if (listener != null) {
                    listener.onValueChanged(xPercent, -yPercent);
                }

                invalidate();
                return true;

            case MotionEvent.ACTION_UP:
                stickPoint.set(centerPoint);
                updateTrianglePaths();
                invalidate();

                if (listener != null) {
                    listener.onReleased();
                }
                return true;
        }
        return super.onTouchEvent(event);
    }

    public void setOnJoystickMoveListener(OnJoystickMoveListener listener) {
        this.listener = listener;
    }
}

2.2  添加属性文件res\values\attrs.xml文件,当外部调用希望通过界面文件在初始化就传入参数的时候,需要添加属性文件。

<resources>
    <declare-styleable name="JoystickView">
        <attr name="stickImage" format="reference" />
    </declare-styleable>
</resources>

2.3  activity_first.xml文件代码,通过设置新建属性可以设置摇杆中心的图片,app:stickImage="@drawable/arr_lr"

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout 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"

    android:orientation="vertical"

    android:background="#FF2F2F2F"
    >



    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="200dp"
        android:orientation="horizontal">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="5"
            android:text="" />
        <com.hy.ble.send.JoystickView
            android:id="@+id/joystickLeft"
            android:layout_width="220dp"
            android:layout_height="200dp"
            app:stickImage="@drawable/arr_fb"
            android:layout_centerInParent="true"

            />

        <TextView

            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="5"
            android:text="" />



        <com.hy.ble.send.JoystickView
            android:id="@+id/joystickRight"
            android:layout_width="200dp"
            android:layout_height="200dp"
            app:stickImage="@drawable/arr_lr"
            android:layout_centerInParent="true"

            />
        <TextView

            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="5"
            android:text="" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="horizontal"
        android:background="@drawable/bottom"
        ></LinearLayout>
</LinearLayout>

2.3  mainactivity.java的调用

package com.hy.ble.send;


import android.Manifest;
import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattServer;
import android.bluetooth.BluetoothGattServerCallback;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.le.AdvertiseCallback;
import android.bluetooth.le.AdvertiseData;
import android.bluetooth.le.AdvertiseSettings;
import android.bluetooth.le.BluetoothLeAdvertiser;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.ColorStateList;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.ParcelUuid;
import android.util.Log;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;

import com.tbruyelle.rxpermissions2.RxPermissions;
import com.trello.rxlifecycle2.android.ActivityEvent;
import com.trello.rxlifecycle2.components.support.RxAppCompatActivity;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;


import butterknife.ButterKnife;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.annotations.Nullable;

public class FirstActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_first);

// 在Activity中初始化两个JoystickView
        JoystickView joystickLeft = findViewById(R.id.joystickLeft);


        JoystickView joystickRight = findViewById(R.id.joystickRight);


// 为左摇杆设置监听
        joystickLeft.setOnJoystickMoveListener(new JoystickView.OnJoystickMoveListener() {
            @Override
            public void onValueChanged(float xPercent, float yPercent) {
                // 这里可以添加控制逻辑,例如:
                // - 控制机器人移动
                // - 控制游戏角色
                // - 控制无人机等

                // 示例:根据摇杆位置控制电机
                if (xPercent > 0.5f) {

                   //向右
                } else if (xPercent < -0.5f) {
                    // 向左转
                }

                if (yPercent > 0.5f) {
                    //前进

                } else if (yPercent < -0.5f) {
                    // 后退

                }

                Log.d("Joystick", "Left - X: " + xPercent + ", Y: " + yPercent);

            }

            @Override
            public void onReleased() {
                // 处理左摇杆释放

                Log.d("JoystickLeft", "Left released");
            }
        });

// 为右摇杆设置监听
        joystickRight.setOnJoystickMoveListener(new JoystickView.OnJoystickMoveListener() {
            @Override
            public void onValueChanged(float xPercent, float yPercent) {
                // 这里可以添加控制逻辑,例如:
                // - 控制机器人移动
                // - 控制游戏角色
                // - 控制无人机等

                // 示例:根据摇杆位置控制电机
                if (xPercent > 0.5f) {
                    // 向右转

                } else if (xPercent < -0.5f) {
                    // 向左转

                }

                if (yPercent > 0.5f) {
                    // 前进

                } else if (yPercent < -0.5f) {
                    // 后退

                }

                Log.d("Joystick", "right - X: " + xPercent + ", Y: " + yPercent);

            }

            @Override
            public void onReleased() {
                // 处理左摇杆释放

                Log.d("JoystickRight", "right released");
            }
        });
       
    }
}

3.效果图

Linux内核支持串口屏,linux串口触摸屏设计总结 Linux serial touch 设计总结概述:最近在做嵌入式linux下串口触摸屏设计,遇到一些问题,经过查找资料和请教同事,总算把问题解决了,事后有把linux相关的内核代码仔细看了一遍,为了有点成果,特别写了个总结。如有任何问题请联系yxj_5421@http://www.doczj.com/doc/87b94b1e227916888486d76d.html,转载请标明出处。系统资源:L... 阅读详情

相关推荐

Chapter 19 Digital Phase-Locked Loops

数字锁相环 Digital Phase-Locked Loops, 就是根据原来时钟信号, 产生新的时钟信号, which is locked or synchronized. (align 参考时钟边沿 or 在中间)

2304_76736886的博客 973

开源 java android app 开发(十六)自定义绘图控件--圆环

本文记录了使用Java开发Android自定义圆环控件DataBoard的详细过程。文章从嵌入式开发转Android开发的背景出发,详细解析了DataBoard控件的实现要点:1.自定义属性定义与初始化;2.视图测量与布局逻辑;3.核心绘制方法实现(包括圆环、渐变边缘和中心文字);4.交互控制功能实现。通过5个关键代码文件(DataBoard.java、MainActivity.java等)完整展示了控件的开发流程,并提供了效果演示说明。该控件支持自定义尺寸、颜色和数值显示,可作为仪表盘等场景的可视化组件。

ajassi2000的博客 1048

告别IMEI!手把手教你用UUID实现Android设备唯一标识(兼容Android 10-13)

本文详细探讨了在Android 10及以上版本中,如何构建合规且高可用的设备唯一标识方案以替代被限制访问的IMEI。文章深入分析了Android设备标识符的演变,并提供了基于UUID/GUID的完整实现策略,包括生成算法、多级持久化存储方案(如MediaStore)、权限处理以及版本兼容性实践,帮助开发者应对Android 10-13的隐私政策变化。

weixin_28339967的博客 574

开源 java android app 开发(十五)自定义绘图控件--仪表盘

本文记录了使用Java开发Android自定义仪表盘控件的学习过程。主要实现了一个可动画化显示数值的DashboardView组件,包含表盘绘制、刻度标记、指针动画等功能。文章详细分析了控件的代码结构,包括属性定义、绘制逻辑、动画实现等核心部分,并提供了完整的源码文件(自定义View、主Activity、布局及资源文件)。该控件支持XML属性配置和动态参数调整,演示了随机数值更新时的平滑指针动画效果。作为嵌入式开发人员临时学习Android开发的实战记录,文章还附有相关技术博客的系列链接。

ajassi2000的博客 1211

大模型-CLIP 详细介绍

最先进的计算机视觉系统通常被训练来预测一组预定义的对象类别。这种受限的监督形式限制了它们的通用性和可用性,因为要指定任何其他视觉概念,就需要额外的标注数据。比如,它们可以识别“猫”、“狗”、“汽车”等。但是,这种做法有一个明显的局限性:如果你想让系统识别一个新的类别,比如说“独角兽”,你就必须提供大量带有“独角兽”标签的图片来训练系统。这不仅耗时费力,而且限制了系统的灵活性和广泛适用性。直接从原始文本中学习关于图像的信息是一种很有前途的替代方案,因为它利用了更广泛的监督来源。

晓的博客 9717

树莓派与ROS2

树莓派与ROS2(Robot Operating System 2)的结合使用为机器人开发、自动化控制以及物联网项目提供了强大的平台。

weixin_47695827的博客 1754

开源 java android app 开发(十四)自定义绘图控件--波形图

本文记录了嵌入式开发者从零开始学习Java Android开发的经验,重点分析了一个自定义波形图控件的实现。该控件采用科幻风格设计,包含网格、坐标轴、多曲线绘制、发光效果和图例等功能。文章详细讲解了初始化流程、数据管理、绘制函数(网格、坐标轴、波形、图例)以及性能优化策略(硬件加速、数据量控制)。同时提供了完整的源码实现,包括WaveView自定义控件、MainActivity主程序及XML布局文件,展示了如何生成随机正弦波、余弦波和噪声波数据并实时显示。该控件适合用于数据可视化场景,具有完整的可扩展性。

ajassi2000的博客 1146

[后端设计]innovus命令editPin详解?

先放命令,有空慢慢写。

m0_61003348的博客 5731

开源 java android app 开发(九)后台之线程和服务

本文记录了Java开发Android App学习经历,重点讲解了后台程序的实现。主要内容包括: 线程与通讯 - 使用Thread、Handler和Looper实现后台线程与主线程通信,通过示例展示了进度条更新功能 服务Service - 详细介绍了Service的创建、绑定及使用方法,包括: Service生命周期管理 Activity与Service的绑定通信 后台任务处理机制 文章提供了完整的代码示例,涵盖XML布局文件、Service实现和Activity交互,适合Android初学者学习后台开发技术

ajassi2000的博客 835

QCustomPlot实现毫秒级时间轴数据的动态可视化与实时刷新优化

本文深入探讨了如何利用QCustomPlot库高效实现毫秒级时间轴数据的动态可视化与实时刷新。文章从基础配置讲起,详细介绍了时间轴初始化、数据平滑滚动、增量更新与内存管理等核心优化技巧,并分享了应对高频数据的缓冲策略及OpenGL硬件加速等高级优化手段,旨在解决实时图表卡顿问题,提升流畅度。

weixin_29012677的博客 424

大样本EEG公共数据集汇总

描述: OpenNeuro平台包含多个认知障碍相关的EEG数据集,例如针对轻度认知障碍(MCI)或阿尔茨海默病(AD)的研究。描述: 天普大学医院EEG语料库包含大量临床EEG记录,可通过元数据筛选出与认知障碍相关的片段(如诊断标签包含dementia或MCI)。描述: ADNI主要提供多模态神经影像数据(MRI/PET),但部分合作研究整合了EEG数据。样本量: 部分数据集包含100+被试(例如结合MRI与EEG的多模态数据)。样本量:30,000+ EEG记录(持续更新,全球最大临床EEG数据库)。

谁人打的太极拳的博客 1759

开源 java android app 开发(七)通讯之Tcp和Http

本文记录了作者从嵌入式软件开发转向Android应用开发的经历,重点介绍了使用Java进行Android开发的学习过程。文章详细描述了开发环境的搭建、工程文件结构、GUI界面布局、文件和数据库存储、多媒体使用等关键步骤,并特别强调了网络通讯协议(如TCP和HTTP)在Android应用中的实际应用。作者通过代码示例展示了如何实现TCP客户端与服务器的通信以及HTTP请求的处理,包括权限配置、界面设计和代码实现。此外,文章还探讨了Android网络安全配置的相关问题,并提供了解决方案。通过这些内容,作者希望记

ajassi2000的博客 1307

CCF编程培训师资认证(PTA)标准(教学能力T)

随着计算机科学的不断发展,计算机相关技术应用到社会各个行业,越来越多的青少年参加到了计算机程序设计的学习中,这对编程培训教师提出了更高的专业要求和职业要求。CCF开展编程培训师资认证项目(Programming Trainer Accreditation,PTA),旨在建立一个规范的、科学的、权威且有公信力的三方认证。认证考试分编程专业能力(P)和教学能力(T)两部分。本标准根据《CCF编程培训师资认证条例》第十条制定,旨在明确教学能力(T)的测试标准。

lan_in的博客 1709

开源 java android app 开发(八)通讯之Mqtt和Ble

本文记录了作者从嵌入式软件开发转向Android应用开发的学习经历,重点介绍了使用Java进行Android开发的关键步骤和技术要点。文章详细描述了开发环境的搭建、工程文件结构、GUI界面布局、常用组件、文件与数据库存储、多媒体使用等内容。特别强调了MQTT和BLE通讯协议的实现,包括MQTT服务器的连接、消息的发送与接收,以及BLE设备的搜索与连接。通过代码示例和配置说明,作者分享了实际开发中的经验与技巧,旨在帮助读者快速掌握Android应用开发的核心技术。

ajassi2000的博客 1047

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

开源 java android app 开发(四)GUI界面重要组件

本文记录了作者从嵌入式软件开发转向Android应用开发的学习经历,重点介绍了在Java环境下使用Android Studio开发应用时涉及的三个重要GUI组件:TabLayout、RecyclerView和BottomNavigationView。TabLayout用于分页显示,RecyclerView用于列表显示并支持点击事件,BottomNavigationView用于底部导航栏。文章详细描述了每个组件的实现步骤,包括创建布局文件、活动代码、适配器以及如何在主活动中集成这些组件。通过具体的代码示例和操

ajassi2000的博客 911

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

开源 java android app 开发(十一)调试、发布

本文记录了一个嵌入式开发人员转学Android应用开发的经历,主要介绍了使用手机调试和生成APK安装包的方法。调试部分详细说明了如何开启手机开发者选项和USB调试模式。APK生成部分则讲解了编译流程和输出文件位置。文章还列出了完整的Java Android开发学习系列链接,涵盖环境搭建、GUI设计、数据存储、网络通讯等核心内容,并推荐了相关的C#.NET开发教程。这些技术笔记既是对学习过程的总结,也为其他开发者提供了实用参考。

ajassi2000的博客 682

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

开源 java android app 开发(十八)最新编译器Android Studio 2025.1.3.7

本文记录了从嵌入式开发转向Android应用开发的学习过程,重点讲解了最新版Android Studio 2025.1.3.7的使用经验。主要内容包括:1)创建Java工程时的语言选择注意事项;2)新版gradle面板设置及混淆封装aar的方法;3)aar库的使用步骤。文中特别强调了新版IDE的配置变化,如gradle面板默认不显示封装库栏目等问题,并提供了解决方案。文章还列出了作者完整的Android开发学习系列文章链接,涵盖环境搭建、UI设计、数据存储、网络通信等全方位内容。

ajassi2000的博客 4618

开源 java android app 开发(十)广播机制

本文记录了Android应用开发中广播机制的学习过程,主要包含两部分内容:一是两个APP之间的广播通讯实现,通过自定义广播发送方(APP1)和接收方(APP2)展示了Intent发送、BroadcastReceiver注册以及跨进程消息传递;二是基于Service和广播机制的网络文件下载系统,使用OkHttp实现带进度显示的APK下载功能,通过广播更新UI进度条,并处理文件存储权限和下载管理。文中详细提供了XML布局、Java代码实现及权限配置,涵盖了广播注册/注销、服务绑定、线程间通信等关键技术点,最后展

ajassi2000的博客 949

开源 java android app 开发(六)多媒体使用

本文记录了作者从嵌入式软件开发转向Android应用开发的经历,重点介绍了使用Java进行Android应用开发的学习过程。文章详细描述了开发环境的搭建、工程文件结构、GUI界面布局及常用组件的使用,以及文件和数据库存储的实现。此外,文章还涵盖了多媒体功能的使用,包括访问手机相册、播放音频和视频的具体实现步骤。通过代码示例和详细说明,作者旨在帮助读者快速掌握Android应用开发的关键技术,并提供了相关开发资源的链接以供参考。

ajassi2000的博客 1039

开源 java android app 开发(一)开发环境的搭建

本文记录了作者从嵌入式软件开发转向Android应用开发的学习经历,重点介绍了Android Studio开发环境的安装与配置过程。文章详细描述了IDE的安装、SDK的安装与配置、环境设置以及Gradle的配置,特别是解决了由于jcenter网站关闭导致的证书错误问题,通过添加阿里云等国内镜像库来确保依赖库的正常拉取。此外,还提到了使用国内镜像加速Gradle的下载,以提高开发效率。本文旨在为遇到类似问题的开发者提供参考和解决方案。

ajassi2000的博客 703

开源 java android app 开发(十二)封库.aar

本文记录了Java Android开发中打包封库的过程,主要解决两种情况:1)简化编译流程时封装不需修改的代码;2)提供SDK时保护源码。通过创建Library模块(包含AddFun和MulFun两个计算类),修改build.gradle开启代码混淆生成.aar库文件。测试工程通过修改gradle配置引入该库,在MainActivity成功调用库中的加减法功能并输出结果,验证了.aar库的有效性。该方案既能提高开发效率,又能实现代码保护。(149字)

ajassi2000的博客 1254

开源 java android app 开发(三)GUI界面布局和常用组件

本文记录了作者从嵌入式软件开发转向Java Android应用开发的学习经历。主要内容集中在GUI界面的布局设计和常用组件的使用,如LinearLayout和TableLayout等布局方法,以及TextView、Button等组件。文章详细描述了如何使用设计器进行界面布局,包括组件的拖放和属性设置,如layout_width和layout_height的配置。此外,还介绍了如何通过代码实现组件间的交互,如按钮点击后修改文本框内容。整体上,文章旨在为初学者提供Android应用开发的基础知识和实用技巧。

ajassi2000的博客 603

开源 java android app 开发(二)工程文件结构

本文记录了作者从嵌入式软件开发转向Android应用开发的经历,重点介绍了Android应用开发中的主要文件和文件夹结构。文章详细描述了权限文件(AndroidManifest.xml)的配置,包括权限管理和界面设置,如横屏显示和隐藏标题栏。此外,还介绍了界面文件夹(XML文件用于GUI设计)、活动文件夹(Java文件,主活动开始执行点)和资源文件夹(包含图片、图标、颜色、字符串等资源)。这些内容旨在帮助开发者快速定位和管理应用开发中的关键组件和资源。

ajassi2000的博客 532

开源 java android app 开发(五)文件和数据库存储

本文记录了作者从嵌入式软件开发转向Android应用开发的学习经历,重点介绍了在Android应用中使用Java进行数据存储的两种方法:SharedPreferences和SQLite3数据库。SharedPreferences用于存储简单的键值对数据,适合保存应用配置和用户偏好设置。SQLite3则是一个轻量级嵌入式数据库,适合处理更复杂的数据存储需求。文章详细展示了如何通过Java代码实现这两种存储方式的基本操作,包括数据的增删改查,并提供了完整的代码示例。通过这些内容,作者希望帮助其他开发者快速掌握A

ajassi2000的博客 584

开源 java android app 开发(十七)封库--混淆源码

本文记录了作者从嵌入式开发转向Android应用开发的学习过程,重点介绍了如何对封装的aar库进行代码混淆保护。文章展示了未混淆aar库的代码可读性问题,详细讲解了通过修改build.gradle配置、设置混淆规则文件,并使用Gradle assembleRelease生成混淆后的aar库的方法。最后通过对比演示,验证了混淆后aar库中的私有变量和方法名称已被替换,有效防止了代码被反向破解,实现了代码保护的目的。

ajassi2000的博客 1246

开源密码管理与双因素认证工具离线镜像合集

本集合汇总等开源密码管理与双因素认证相关离线包。侧重密码箱与 2FA,与「安全审计/渗透扫描」合集错开。

230
上一篇: 开源 python 应用 开发(二)基于pyautogui、open cv 视觉识别的工具自动化
下一篇: 开源 C# .net mvc 开发(六)发送邮件、定时以及CMD编程
ajassi2000
博客等级 码龄22年 2033粉丝 191原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值