当前位置: 首页 > news >正文

Android学习总结之自定义View实战篇

 场景一:自定义进度条

在很多应用中,我们会看到一些独特样式的进度条,接下来就实现一个简单的圆形进度条。

实现思路
  • 继承 View 类。
  • 重写 onDraw 方法,在该方法里使用 Canvas 和 Paint 来绘制圆形进度条。
  • 提供更新进度的方法。
示例代码
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;

public class CustomProgressBar extends View {
    private Paint backgroundPaint;
    private Paint progressPaint;
    private int progress = 0;
    private RectF rectF;

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

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

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

    private void init() {
        backgroundPaint = new Paint();
        backgroundPaint.setColor(Color.GRAY);
        backgroundPaint.setStyle(Paint.Style.STROKE);
        backgroundPaint.setStrokeWidth(20);
        backgroundPaint.setAntiAlias(true);

        progressPaint = new Paint();
        progressPaint.setColor(Color.BLUE);
        progressPaint.setStyle(Paint.Style.STROKE);
        progressPaint.setStrokeWidth(20);
        progressPaint.setAntiAlias(true);

        rectF = new RectF();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        int centerX = getWidth() / 2;
        int centerY = getHeight() / 2;
        int radius = Math.min(centerX, centerY) - 20;

        rectF.set(centerX - radius, centerY - radius, centerX + radius, centerY + radius);

        // 绘制背景圆形
        canvas.drawArc(rectF, 0, 360, false, backgroundPaint);

        // 绘制进度弧形
        float sweepAngle = (progress / 100.0f) * 360;
        canvas.drawArc(rectF, -90, sweepAngle, false, progressPaint);
    }

    public void setProgress(int progress) {
        if (progress < 0) {
            progress = 0;
        } else if (progress > 100) {
            progress = 100;
        }
        this.progress = progress;
        invalidate();
    }
}    

在布局文件中使用

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:gravity="center">

    <com.example.customview.CustomProgressBar
        android:id="@+id/customProgressBar"
        android:layout_width="200dp"
        android:layout_height="200dp" />
</LinearLayout>

在 Activity 中更新进度 

import android.os.Bundle;
import android.os.Handler;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {
    private CustomProgressBar customProgressBar;
    private int currentProgress = 0;
    private Handler handler = new Handler();

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

        customProgressBar = findViewById(R.id.customProgressBar);

        // 模拟进度更新
        new Thread(() -> {
            while (currentProgress < 100) {
                currentProgress++;
                handler.post(() -> customProgressBar.setProgress(currentProgress));
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            handler.post(() -> Toast.makeText(MainActivity.this, "进度完成", Toast.LENGTH_SHORT).show());
        }).start();
    }
}

场景二:自定义星级评分控件

在电商、社交等应用里,星级评分控件是很常见的。下面来实现一个简单的星级评分控件。

实现思路
  • 继承 View 类。
  • 重写 onDraw 方法,绘制星星图标。
  • 重写 onTouchEvent 方法,处理触摸事件,实现星级选择。
示例代码

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

import androidx.core.content.ContextCompat;

public class CustomStarRating extends View {
    private Drawable starFilled;
    private Drawable starEmpty;
    private int starCount = 5;
    private int rating = 0;
    private int starSize = 50;
    private int starSpacing = 10;

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

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

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

    private void init() {
        starFilled = ContextCompat.getDrawable(getContext(), android.R.drawable.star_big_on);
        starEmpty = ContextCompat.getDrawable(getContext(), android.R.drawable.star_big_off);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        for (int i = 0; i < starCount; i++) {
            int left = i * (starSize + starSpacing);
            int top = 0;
            int right = left + starSize;
            int bottom = top + starSize;

            Drawable drawable = (i < rating) ? starFilled : starEmpty;
            drawable.setBounds(left, top, right, bottom);
            drawable.draw(canvas);
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            float x = event.getX();
            int newRating = (int) (x / (starSize + starSpacing)) + 1;
            if (newRating > starCount) {
                newRating = starCount;
            } else if (newRating < 0) {
                newRating = 0;
            }
            rating = newRating;
            invalidate();
            return true;
        }
        return super.onTouchEvent(event);
    }

    public int getRating() {
        return rating;
    }

    public void setRating(int rating) {
        if (rating < 0) {
            rating = 0;
        } else if (rating > starCount) {
            rating = starCount;
        }
        this.rating = rating;
        invalidate();
    }
}    

在布局文件中使用 

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:gravity="center">

    <com.example.customview.CustomStarRating
        android:id="@+id/customStarRating"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</LinearLayout>

在 Activity 中获取评分 

import android.os.Bundle;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {
    private CustomStarRating customStarRating;

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

        customStarRating = findViewById(R.id.customStarRating);

        // 设置初始评分
        customStarRating.setRating(3);

        // 获取评分
        int rating = customStarRating.getRating();
        Toast.makeText(this, "当前评分:" + rating, Toast.LENGTH_SHORT).show();
    }
}

场景三:实现一个自定义的圆角ImageView

实现思路
  1. 继承 ImageView:创建一个新的类,继承自 ImageView
  2. 重写 onDraw 方法:在 onDraw 方法里,运用 Canvas 和 Paint 来绘制圆角矩形,并且把图片绘制到这个圆角矩形内。
  3. 处理图片缩放:要保证图片能够正确地缩放以适应圆角矩形。
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.util.AttributeSet;
import androidx.appcompat.widget.AppCompatImageView;

public class RoundedImageView extends AppCompatImageView {
    private float cornerRadius = 20; // 默认圆角半径

    public RoundedImageView(Context context) {
        super(context);
    }

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

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

    private void init(Context context, AttributeSet attrs) {
        // 可以在这里从属性中获取圆角半径
        // TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.RoundedImageView);
        // cornerRadius = a.getDimension(R.styleable.RoundedImageView_cornerRadius, cornerRadius);
        // a.recycle();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        int width = getWidth();
        int height = getHeight();

        // 创建一个圆角矩形路径
        Path path = new Path();
        RectF rect = new RectF(0, 0, width, height);
        path.addRoundRect(rect, cornerRadius, cornerRadius, Path.Direction.CW);
        canvas.clipPath(path);

        super.onDraw(canvas);
    }

    public void setCornerRadius(float radius) {
        this.cornerRadius = radius;
        invalidate();
    }
}    

使用方法

在布局文件中使用自定义的 RoundedImageView

<com.example.yourpackage.RoundedImageView
    android:layout_width="200dp"
    android:layout_height="200dp"
    android:src="@drawable/your_image" />    

代码解释

  1. RoundedImageView 类:继承自 AppCompatImageView,它是 ImageView 的兼容版本。
  2. cornerRadius 变量:用来存储圆角的半径,默认值为 20。
  3. init 方法:能够从属性中获取圆角半径,不过当前处于注释状态。
  4. onDraw 方法
    • 创建一个圆角矩形路径。
    • 运用 canvas.clipPath 方法把画布裁剪成圆角矩形。
    • 调用 super.onDraw(canvas) 来绘制图片。
  5. setCornerRadius 方法:用于动态设置圆角半径,并且调用 invalidate 方法重新绘制视图。

之后还会有补充的,感谢观看!!!

http://www.dtcms.com/a/122126.html

相关文章:

  • 探究按摩养生门店危机:上门服务成 “搅局者”
  • Python安装软件包报错 fatal error: Python.h: No such file or directory
  • python reportlab模块----操作PDF文件
  • 请回答集成测试和系统测试的区别,以及它们的应用场景主要是什么?
  • 解决华硕主板Z890m下载ubuntu20.04后没有以太网问题
  • 【免费】在线工具网址
  • CSS空间转换
  • 第十四届蓝桥杯Scratch03月stema选拔赛真题——绘制彩虹
  • pycharm编译部署智能合约(solcx与web3搭配)
  • crossorigin是什么?【你了解前端的crossorigin吗?!】
  • mapbox基础,加载F4Map二维地图
  • Scala相关知识学习总结6
  • GPT-4o-image模型:开启AI图片编辑新时代
  • Windows Terminal 美化增强攻略 2.0:打造个性化高效开发环境(快捷键介绍、编程语言环境、starship美化、高效命令行工具)
  • TCP的三次握手和四次挥手
  • Visual Studio未能加载相应的Package包弹窗报错
  • HarmonyOS:使用geoLocationManager (位置服务)获取位置信息
  • ES6规范新特性总结
  • WebView2最低支持.NET frame4.5,win7系统
  • Linux基础IO(三)之访问文件的本质
  • GaussDB使用指南
  • FFmpeg安装和使用
  • # 基于BERT的文本分类
  • 龙蜥社区荣获 OS2ATC 2025 “最具影响力开源创新贡献奖”
  • spark数据清洗案例:流量统计
  • 力扣刷题-热题100题-第34题(c++、python)
  • 机器学习代码基础——ML2 使用梯度下降的线性回归
  • 暑假实习面试复盘
  • Vue框架的Diff算法
  • 使用Ollama通过预训练模型获取句子向量(rest api方式)