Android自定义View全解析:从基础绘制到复杂交互,实战多种自定义View实现

在Android开发中,自定义View的应用场景非常广泛。根据不同的需求,开发者可以创建各种类型的自定义View。以下是几种常见的自定义View类型及其实现思路和示例。
1. 自定义绘制View

自定义绘制View是最基础的自定义View类型,通常用于绘制图形、文本、图像等内容。开发者通过重写onDraw()方法,使用Canvas和Paint来实现绘制。

示例:自定义圆形View

复制代码
public class CircleView extends View {
    private Paint paint;

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

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

    private void init() {
        paint = new Paint();
        paint.setColor(Color.RED);
        paint.setStyle(Paint.Style.FILL);
        paint.setAntiAlias(true); // 抗锯齿
    }

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

使用:

复制代码
<com.example.CircleView
    android:layout_width="100dp"
    android:layout_height="100dp"/>

2. 自定义组合View

自定义组合View是通过将多个现有的View组合在一起,形成一个新的复合View。这种方式通常用于创建复杂的UI组件。

示例:自定义标题栏

复制代码
public class CustomTitleBar extends RelativeLayout {
    private TextView titleText;
    private ImageView backButton;

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

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

    private void init(Context context) {
        LayoutInflater.from(context).inflate(R.layout.custom_title_bar, this, true);
        titleText = findViewById(R.id.titleText);
        backButton = findViewById(R.id.backButton);

        backButton.setOnClickListener(v -> {
            // 返回按钮点击事件
            if (context instanceof Activity) {
                ((Activity) context).finish();
            }
        });
    }

    public void setTitle(String title) {
        titleText.setText(title);
    }
}

布局文件:custom_title_bar.xml

复制代码
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="50dp"
    android:background="@color/colorPrimary">

    <ImageView
        android:id="@+id/backButton"
        android:layout_width="30dp"
        android:layout_height="30dp"
        android:layout_centerVertical="true"
        android:layout_marginStart="10dp"
        android:src="@drawable/ic_back" />

    <TextView
        android:id="@+id/titleText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:textColor="@android:color/white"
        android:textSize="18sp" />
</RelativeLayout>

使用:

复制代码
<com.example.CustomTitleBar
    android:id="@+id/titleBar"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"/>

3. 自定义动画View

自定义动画View通常用于实现复杂的动画效果。开发者可以通过ValueAnimator、ObjectAnimator或PropertyValuesHolder等工具来实现动画。

示例:自定义旋转进度条

复制代码
public class RotatingProgressBar extends View {
    private Paint paint;
    private float rotationAngle = 0;

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

    public RotatingProgressBar(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(10);
        paint.setAntiAlias(true);
    }

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

        canvas.save();
        canvas.rotate(rotationAngle, centerX, centerY);
        canvas.drawCircle(centerX, centerY, radius, paint);
        canvas.restore();
    }

    public void startRotation() {
        ValueAnimator animator = ValueAnimator.ofFloat(0, 360);
        animator.setDuration(1000);
        animator.setRepeatCount(ValueAnimator.INFINITE);
        animator.addUpdateListener(animation -> {
            rotationAngle = (float) animation.getAnimatedValue();
            invalidate();
        });
        animator.start();
    }
}

使用:

复制代码
RotatingProgressBar progressBar = findViewById(R.id.rotatingProgressBar);
progressBar.startRotation();

4. 自定义触摸交互View

自定义触摸交互View通常用于处理用户的触摸事件,例如拖动、缩放、点击等。

示例:自定义可拖动View

复制代码
public class DraggableView extends View {
    private float lastX, lastY;

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

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

    private void init() {
        setBackgroundColor(Color.GREEN);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                lastX = event.getX();
                lastY = event.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                float dx = event.getX() - lastX;
                float dy = event.getY() - lastY;
                setX(getX() + dx);
                setY(getY() + dy);
                break;
        }
        return true;
    }
}

使用:

复制代码
<com.example.DraggableView
    android:layout_width="100dp"
    android:layout_height="100dp"/>

5. 自定义属性View

自定义属性View允许开发者在XML中定义和使用自定义属性,以增强View的灵活性。

示例:自定义带属性的TextView
在res/values/attrs.xml中定义属性

复制代码
<declare-styleable name="CustomTextView">
    <attr name="customTextColor" format="color" />
    <attr name="customTextSize" format="dimension" />
</declare-styleable>

在自定义View中解析属性:

复制代码
public class CustomTextView extends TextView {
    public CustomTextView(Context context) {
        super(context);
        init(null);
    }

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

    private void init(AttributeSet attrs) {
        if (attrs != null) {
            TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.CustomTextView);
            int textColor = a.getColor(R.styleable.CustomTextView_customTextColor, Color.BLACK);
            float textSize = a.getDimension(R.styleable.CustomTextView_customTextSize, 16);
            a.recycle();

            setTextColor(textColor);
            setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
        }
    }
}

在XML中使用:

复制代码
<com.example.CustomTextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Hello World"
    app:customTextColor="@color/red"
    app:customTextSize="20sp"/>

6. 自定义ViewGroup

自定义ViewGroup用于实现复杂的布局逻辑,例如瀑布流布局、环形布局等。

示例:自定义流式布局

复制代码
public class FlowLayout extends ViewGroup {
    public FlowLayout(Context context) {
        super(context);
    }

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

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        int childCount = getChildCount();
        int width = r - l;
        int x = 0, y = 0;

        for (int i = 0; i < childCount; i++) {
            View child = getChildAt(i);
            if (x + child.getMeasuredWidth() > width) {
                x = 0;
                y += child.getMeasuredHeight();
            }
            child.layout(x, y, x + child.getMeasuredWidth(), y + child.getMeasuredHeight());
            x += child.getMeasuredWidth();
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        measureChildren(widthMeasureSpec, heightMeasureSpec);
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }
}

使用:

复制代码
<com.example.FlowLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
    <!-- 添加子View -->
</com.example.FlowLayout>

总结

自定义View的类型多种多样,开发者可以根据具体需求选择合适的实现方式。无论是简单的绘制、复杂的动画,还是自定义布局,掌握自定义View的开发技巧都能极大地提升应用的灵活性和用户体验。

相关推荐
是店小二呀44 分钟前
【算法-链表】链表操作技巧:常见算法
android·c++·算法·链表
南玖yy2 小时前
C++ 工具链与开发实践:构建安全、高效与创新的开发生态
开发语言·c++·人工智能·后端·安全·架构·交互
zhifanxu2 小时前
Kotlin 遍历
android·开发语言·kotlin
追随远方3 小时前
Android NDK版本迭代与FFmpeg交叉编译完全指南
android·ffmpeg
柯南二号13 小时前
Android Studio根目录下创建多个可运行的模块
android·ide·android studio
恋猫de小郭16 小时前
Compose Multiplatform iOS 稳定版发布:可用于生产环境,并支持 hotload
android·flutter·macos·ios·kotlin·cocoa
音视频牛哥18 小时前
把Android设备变成“国标摄像头”:GB28181移动终端实战接入指南
android·音视频·大牛直播sdk·gb28181安卓端·gb28181对接·gb28181平台对接·gb28181监控
tangweiguo0305198718 小时前
Jetpack Compose 响应式布局实战:BoxWithConstraints 完全指南
android
難釋懷19 小时前
Android开发-视图基础
android
淺黙ベ20 小时前
✍️【TS类型体操进阶】挑战类型极限,成为类型魔法师!♂️✨
前端·vue.js·typescript·交互