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

Android的第一次面试(Java篇)

   在 Android 开发中,View 是用户界面的基础组件,理解 View 的绘制原理以及如何自定义 View 是实现独特界面效果的关键。本文将深入探讨 Android View 的绘制流程、自定义 View 的工作原理,并通过具体的代码示例来展示如何实现自定义 View。

Android View 的绘制流程

整体流程概述

Android View 的绘制主要分为三个步骤:测量(measure)、布局(layout)和绘制(draw),这三个步骤依次执行,完成 View 在屏幕上的显示。

 测量(measure)

测量过程决定了 View 的大小。系统会调用measure(int widthMeasureSpec, int heightMeasureSpec)方法,其中widthMeasureSpecheightMeasureSpec是测量规格,包含了测量模式和大小信息。测量模式有三种:

  • EXACTLY:精确值模式,父容器已经为子 View 指定了确切的大小。
  • AT_MOST:最大值模式,子 View 的大小不能超过父容器指定的大小。
  • UNSPECIFIED:未指定模式,父容器没有对 View 的大小做限制。
布局(layout)

布局过程决定了 View 在父容器中的位置。系统会调用layout(int left, int top, int right, int bottom)方法,其中lefttoprightbottom分别表示 View 相对于父容器的左、上、右、下边界的坐标。

 绘制(draw)

绘制过程将 View 绘制到屏幕上。系统会调用draw(Canvas canvas)方法,通过Canvas对象进行绘制操作,如绘制图形、文本等。

具体代码示例

以下是一个简单的自定义 View,展示了测量、布局和绘制的基本实现:

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;

public class CustomView extends View {
    private Paint mPaint;

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

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

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

    private void init() {
        mPaint = new Paint();
        mPaint.setColor(Color.RED);
        mPaint.setStyle(Paint.Style.FILL);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int width = MeasureSpec.getSize(widthMeasureSpec);
        int height = MeasureSpec.getSize(heightMeasureSpec);
        setMeasuredDimension(width, height);
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
    }

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

在上述代码中:

  • init()方法用于初始化画笔。
  • onMeasure()方法根据测量规格确定 View 的大小。
  • onLayout()方法调用父类的onLayout()方法,完成布局操作。
  • onDraw()方法在画布上绘制一个红色的圆形。

自定义 View 的工作原理

 继承 View 类

自定义 View 通常需要继承自View类或其子类,如TextViewImageView等。通过重写onMeasure()onLayout()onDraw()方法,可以实现自定义的测量、布局和绘制逻辑。

处理属性

可以通过自定义属性来为自定义 View 添加额外的配置选项。具体步骤如下:

  1. res/values目录下创建attrs.xml文件,定义自定义属性:
<resources>
    <declare-styleable name="CustomView">
        <attr name="circleColor" format="color" />
    </declare-styleable>
</resources>

在自定义 View 的构造方法中获取属性值:

public CustomView(Context context, AttributeSet attrs) {
    super(context, attrs);
    TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CustomView);
    int circleColor = typedArray.getColor(R.styleable.CustomView_circleColor, Color.RED);
    typedArray.recycle();

    mPaint = new Paint();
    mPaint.setColor(circleColor);
    mPaint.setStyle(Paint.Style.FILL);
}

在布局文件中使用自定义属性:

<com.example.customview.CustomView
    android:layout_width="200dp"
    android:layout_height="200dp"
    app:circleColor="@color/blue" />

事件处理

自定义 View 还可以处理用户的触摸事件,通过重写onTouchEvent(MotionEvent event)方法来实现

@Override
public boolean onTouchEvent(MotionEvent event) {
    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            // 处理按下事件
            break;
        case MotionEvent.ACTION_MOVE:
            // 处理移动事件
            break;
        case MotionEvent.ACTION_UP:
            // 处理抬起事件
            break;
    }
    return true;
}

实战扩展:

  如果我要一个可以滑动的波浪形进度条怎么实现?

  实现一个可以滑动的波浪形进度条,你可以通过自定义 View 来完成。 

实现思路

  1. 绘制波浪:使用正弦函数来生成波浪的形状,并使用 Canvas 进行绘制。
  2. 实现滑动:通过监听触摸事件,根据触摸位置的变化来更新进度条的进度。
  3. 更新波浪:根据进度条的进度,动态更新波浪的位置和高度。

 示例代码:

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

public class WaveProgressBar extends View {
    private Paint mWavePaint;
    private Path mWavePath;
    private float mProgress = 0; // 进度值,范围 0 - 1
    private float mWaveOffset = 0; // 波浪的偏移量
    private float mWaveHeight = 20; // 波浪的高度
    private float mWaveLength = 200; // 波浪的波长

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

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

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

    private void init() {
        mWavePaint = new Paint();
        mWavePaint.setColor(Color.BLUE);
        mWavePaint.setStyle(Paint.Style.FILL);
        mWavePath = new Path();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        mWavePath.reset();
        int width = getWidth();
        int height = getHeight();
        float progressHeight = height * mProgress;

        // 绘制波浪
        mWavePath.moveTo(0, height);
        for (float x = 0; x <= width; x++) {
            float y = (float) (progressHeight + mWaveHeight * Math.sin((x + mWaveOffset) * 2 * Math.PI / mWaveLength));
            mWavePath.lineTo(x, y);
        }
        mWavePath.lineTo(width, height);
        mWavePath.close();

        canvas.drawPath(mWavePath, mWavePaint);

        // 更新波浪偏移量,实现波浪滚动效果
        mWaveOffset += 5;
        if (mWaveOffset > mWaveLength) {
            mWaveOffset = 0;
        }
        invalidate(); // 触发重绘
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
            case MotionEvent.ACTION_MOVE:
                float x = event.getX();
                mProgress = Math.max(0, Math.min(1, x / getWidth()));
                invalidate();
                return true;
            case MotionEvent.ACTION_UP:
                return true;
        }
        return super.onTouchEvent(event);
    }

    public void setProgress(float progress) {
        this.mProgress = Math.max(0, Math.min(1, progress));
        invalidate();
    }

    public float getProgress() {
        return mProgress;
    }
}

使用方法

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

<com.example.yourpackage.WaveProgressBar
    android:layout_width="match_parent"
    android:layout_height="200dp" />

代码解释

  1. 初始化:在 init() 方法中初始化画笔和路径。
  2. 绘制波浪:在 onDraw() 方法中,使用正弦函数生成波浪的形状,并使用 Path 记录波浪的路径,最后使用 Canvas 绘制路径。
  3. 更新波浪偏移量:在 onDraw() 方法中,每次绘制时更新波浪的偏移量,并调用 invalidate() 方法触发重绘,实现波浪滚动的效果。
  4. 处理触摸事件:在 onTouchEvent() 方法中,监听触摸事件,根据触摸位置的变化更新进度条的进度,并调用 invalidate() 方法触发重绘。
  5. 设置和获取进度:提供 setProgress() 和 getProgress() 方法,用于设置和获取进度条的进度。

  通过以上步骤,你就可以实现一个可以滑动的波浪形进度条。

   总结:

   自定义 View 的工作原理主要基于继承 View 类,重写关键方法如 onMeasureonLayout 和 onDraw 来完成测量、布局和绘制操作,还可通过自定义属性丰富配置,重写事件处理方法响应交互。基于此原理,我们利用正弦曲线生成波浪形状,在 onDraw 方法中动态绘制波浪,结合重写 onTouchEvent 方法响应触摸操作,从而实现可滑动且带有滚动效果的波浪形进度条。


http://www.kler.cn/a/585777.html

相关文章:

  • 为什么 JPA 可以通过 findByNameContaining 自动生成 SQL 语句?
  • 如何在PHP中实现数据加密与解密:保护敏感信息
  • 小语言模型(SLM)技术解析:如何在有限资源下实现高效AI推理
  • 《CircleCI:CircleCI:解锁软件开发持续集成(CI)和持续部署(CD)高效密码》:此文为AI自动生成
  • Windows 上安装配置 Maven
  • WVP前后端部署
  • Java 大视界 -- Java 大数据分布式计算中的资源调度与优化策略(131)
  • 基于Python的物联网智慧农业数据采集与管理系统设计方案
  • 登录认证-登录校验-Filter
  • c++常用的算术生成算法
  • Kotlin apply 方法的用法和使用场景
  • Windows10安装Rust 和ZED(失败)
  • 基于Python+MySQL编写的(WinForm)图书管理系统
  • C语言零基础入门:嵌入式系统开发之旅
  • CSS 的 inherit、initial、revert 和 unset区别
  • 工作记录 2017-01-12
  • package.json 依赖包约束及快速删除node_modules
  • 【实战ES】实战 Elasticsearch:快速上手与深度实践-8.2.2成本优化与冷热数据分离
  • c++介绍锁 一
  • ECU BootLoader开发——Flash编程