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的开发技巧都能极大地提升应用的灵活性和用户体验。

相关推荐
然后就去远行吧1 小时前
小程序 wxml 语法 —— 37 setData() - 修改对象类型数据
android·前端·小程序
熙曦Sakura1 小时前
【MySQL】数据类型
android·mysql·adb
故事与他6451 小时前
CTFHub-上传文件
android·ide·windows·web安全·网络安全·android studio·xss
大胃粥2 小时前
Android app 冷启动(7) 执行动画
android
yi诺千金2 小时前
Android U 分屏——SystemUI侧处理
android
顾林海2 小时前
Flutter Dart 流程控制语句详解
android·前端·flutter
Cui晨2 小时前
Android 滑块开关 自定义Switch
android
&有梦想的咸鱼&2 小时前
Android Retrofit 框架注解定义与解析模块深度剖析(一)
android·retrofit
烬奇小云2 小时前
安卓7.0到11.0的更新变化(简单理解)
android·安卓逆向
whatever who cares2 小时前
android:实现圆角效果
android