Android开发小知识3—自定义View

前言

当android系统的UI不能满足我们的设计或需求时,我们就需要自定义view来实现我们的目的,今天打算总结一下自定义view的几种常见方式。在此之前,学习了http://www.cnblogs.com/jiayongji/p/5560806.html 。受益良多,本文有参考其中的内容。

三种方式

自定义控件的实现有三种方式:组合控件、自绘控件和继承控件。下面将分别对这三种方式进行介绍。

组合控件

组合控件,即将本有的控件组合起来使用,形成新的控件。下面给大家介绍一种标题组合控件。

1、布局文件,可以在这个地方将控件组合起来使用,形成新的控件。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="55dp"
    android:background="#808080"
    android:orientation="horizontal">

    <ImageView
        android:id="@+id/back"
        android:layout_width="30dp"
        android:layout_height="30dp"
        android:layout_marginLeft="10dp"
        android:layout_marginTop="10dp"
        android:src="@drawable/back" />

    <TextView
        android:id="@+id/title_text"
        android:layout_width="0dp"
        android:layout_height="30dp"
        android:layout_marginLeft="10dp"
        android:layout_marginTop="10dp"
        android:layout_weight="1"
        android:ellipsize="end"
        android:gravity="center_vertical"
        android:maxLines="1"
        android:textColor="#ffffff"
        android:textSize="18dp"
        android:textStyle="bold"
        tools:text="TITLE" />

    <TextView
        android:id="@+id/right_text"
        android:layout_width="wrap_content"
        android:layout_height="30dp"
        android:layout_marginRight="10dp"
        android:layout_marginTop="10dp"
        android:gravity="center_vertical"
        android:textColor="#ffffff"
        android:textSize="14dp"
        android:textStyle="bold"
        tools:text="编辑" />
</LinearLayout>

2、创建一个类CustomTitleView ,继承自RelativeLayout:

import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
 
public class CustomTitleView extends RelativeLayout {

    private ImageView back;
    private TextView title;
    private TextView rightText;
    private TitleListener listener;

    public CustomTitleView(Context context) {
        this(context, null);
    }

    public CustomTitleView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public CustomTitleView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        View.inflate(context, R.layout.view_title, this);
        initView();
        setEvent();
    }

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

    public void setListener(TitleListener listener) {
        this.listener = listener;
    }

    private void initView() {
        back = (ImageView) findViewById(R.id.back);
        title = (TextView) findViewById(R.id.title_text);
        rightText = (TextView) findViewById(R.id.right_text);

    }

    private void setEvent() {
        back.setOnClickListener(v -> listener.onBack());
        rightText.setOnClickListener(v -> listener.onRight());
    }

    public interface TitleListener {
        void onBack();

        void onRight();
    }
}

3、以上,我们的组合控件View就已经完成,使用也很方便,如下:

 title = (CustomTitleView) findViewById(R.id.title);
        title.setTitleData("TEST");
        title.setListener(new CustomTitleView.TitleListener() {
            @Override
            public void onBack() {
                finish();
            }

            @Override
            public void onRight() {
                //no-op
            }
        });

4、运行效果如下:


组合控件

继承控件

继承控件就是,继承已有的控件,保留需要的功能,引入新的特性。这种自定义方法是最常见,使用最广泛的。比如说自定义Dialog等。

1、创建dialog的布局文件

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ImageView
        android:id="@+id/background_image"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/transparent_half"
        android:scaleType="fitXY" />

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:layout_marginLeft="@dimen/margin40"
        android:layout_marginRight="@dimen/margin40"
        android:background="@drawable/shape_frame_gray_background_white">

        <TextView
            android:id="@+id/dialog_title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerHorizontal="true"
            android:layout_marginEnd="@dimen/margin10"
            android:layout_marginStart="@dimen/margin10"
            android:layout_marginTop="@dimen/margin20"
            android:gravity="center"
            android:textColor="@color/dark_gray"
            android:textSize="@dimen/text_size17"
            tools:text="Logout" />

        <TextView
            android:id="@+id/dialog_content"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@+id/dialog_title"
            android:layout_centerHorizontal="true"
            android:layout_marginBottom="@dimen/margin30"
            android:layout_marginEnd="@dimen/margin10"
            android:layout_marginStart="@dimen/margin10"
            android:layout_marginTop="@dimen/margin30"
            android:gravity="center"
            android:textColor="@color/dark_gray"
            android:textSize="@dimen/text_size13"
            tools:text="Are you sure you want to log out?" />

        <View
            android:id="@+id/line_transverse"
            android:layout_width="match_parent"
            android:layout_height="@dimen/height1"
            android:layout_below="@+id/dialog_content"
            android:background="@color/gray_dialog" />

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_below="@+id/line_transverse">

            <Button
                android:id="@+id/right_button"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_alignParentEnd="true"
                android:layout_toEndOf="@+id/line_vertical"
                android:background="@color/transparent"
                android:text="@string/dialog_yes"
                android:textAllCaps="false"
                android:textColor="@color/blue"
                android:textSize="@dimen/text_size17" />

            <View
                android:id="@+id/line_vertical"
                android:layout_width="@dimen/height1"
                android:layout_height="@dimen/layout_height54"
                android:layout_centerInParent="true"
                android:background="@color/gray_dialog" />

            <Button
                android:id="@+id/left_button"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_toStartOf="@+id/line_vertical"
                android:background="@color/transparent"
                android:text="@string/dialog_no"
                android:textAllCaps="false"
                android:textColor="@color/blue"
                android:textSize="@dimen/text_size17" />
        </RelativeLayout>
    </RelativeLayout>
</RelativeLayout>

2、创建CustomDialog类,继承自Dialog,并实现需要的一些接口。

public class LikeIosDialog extends Dialog {

    public LikeIosDialog(Context context, int theme) {
        super(context, theme);
    }

    public void onDismiss() {
        if (isShowing()) {
            dismiss();
        }
    }

    public static class Builder {
        private Button leftButton;
        private Button rightButton;
        private TextView dialogTitle;
        private TextView dialogContent;
        private View lineVertical;

        private String message;
        private String title;
        private String leftButtonText;
        private String rightButtonText;
        private View.OnClickListener leftButtonClickListener;
        private View.OnClickListener rightButtonClickListener;
        private boolean isSingle = false;

        private View layout;
        private LikeIosDialog dialog;

        public Builder(Context context) {
            dialog = new LikeIosDialog(context, R.style.Dialog);
            LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            layout = inflater.inflate(R.layout.layout_dialog, null);
            dialog.addContentView(layout, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
            dialog.setContentView(layout);
            dialog.setCancelable(true);
            dialog.setCanceledOnTouchOutside(false);
        }

        public LikeIosDialog createDialog() {
            initView();
            setText();
            setEvent();
            return dialog;
        }

        private void initView() {
            leftButton = (Button) layout.findViewById(R.id.left_button);
            rightButton = (Button) layout.findViewById(R.id.right_button);
            dialogContent = (TextView) layout.findViewById(R.id.dialog_content);
            dialogTitle = (TextView) layout.findViewById(R.id.dialog_title);
            lineVertical = layout.findViewById(R.id.line_vertical);
        }

        private void setText() {
            if (isSingle) {
                leftButton.setVisibility(View.GONE);
                lineVertical.setVisibility(View.GONE);
            } else {
                leftButton.setVisibility(View.VISIBLE);
                lineVertical.setVisibility(View.VISIBLE);
            }
            dialogContent.setText(message);
            leftButton.setText(leftButtonText);
            rightButton.setText(rightButtonText);
            dialogTitle.setText(title);
        }

        private void setEvent() {
            leftButton.setOnClickListener(leftButtonClickListener);
            rightButton.setOnClickListener(rightButtonClickListener);
        }

        public Builder setMessage(String message) {
            this.message = message;
            return this;
        }

        public Builder setTitle(String title) {
            this.title = title;
            return this;
        }

        public Builder setLeftButton(String leftButtonText, View.OnClickListener leftButtonClickListener) {
            this.leftButtonText = leftButtonText;
            this.leftButtonClickListener = leftButtonClickListener;
            return this;
        }

        public Builder setRightButton(String rightButtonText, View.OnClickListener rightButtonClickListener) {
            this.rightButtonText = rightButtonText;
            this.rightButtonClickListener = rightButtonClickListener;
            return this;
        }

        public Builder isSingleButton(boolean isSingleButton) {
            this.isSingle = isSingleButton;
            return this;
        }

        public Builder setSingleButton(String rightButtonText, View.OnClickListener rightButtonClickListener) {
            this.rightButtonText = rightButtonText;
            this.rightButtonClickListener = rightButtonClickListener;
            return this;
        }
    }

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_BACK) {
            dismiss();
        }
        return super.onKeyDown(keyCode, event);
    }
}

3、使用

private BukkaDialog.Builder deleteDialogBuilder;
private BukkaDialog deleteDialog;
 
deleteDialogBuilder = new BukkaDialog.Builder(this);
deleteDialog = deleteDialogBuilder
                .setTitle(getString(R.string.dialog_title))
                .setMessage(getString(R.string.dialog_content))
                .isSingleButton(false)
                .setRightButton(getString(R.string.ok), v1 -> {
                   //TODO something
                    deleteDialog.onDismiss();
                })
                .setLeftButton(getString(R.string.cancel), v12 -> deleteDialog.onDismiss())
                .createDialog();
        deleteDialog.show();

4、运行效果如下:


继承控件

自绘控件

自绘控件的内容都是自己绘制出来的,在View的onDraw方法中完成绘制。在自定义View中,难度最大,但是效果最好的一种方法,下面就实现一个简单圆圈的画法。

1、创建CounterView类,继承自View,同时可以实现OnClickListener等接口:

package com.monoqn.widgets;

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

public class CounterView extends View {

    private Paint mPaint;
    private Context mContext;
    private int screenWidth;
    private int screenHeight;

    public CounterView(Context context) {
        super(context, null);
        init();
    }

    public CounterView(Context context, AttributeSet attrs) {
        super(context, attrs);
        mContext = context;
        init();
    }

    private void init() {
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setColor(Color.RED);

        mPaint.setStyle(Paint.Style.STROKE);

        mPaint.setStrokeWidth(20);

        WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
        Display display = wm.getDefaultDisplay();
        screenWidth = display.getWidth();
        screenHeight = display.getHeight();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawCircle(screenWidth / 2, screenHeight / 2, 50, mPaint);
    }
}

2、在activity_main.xml中引入该自定义布局:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#ffffff"
    android:orientation="vertical">

    <com.monoqn.widgets.CounterView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center" />
</FrameLayout>

3、运行效果如下:


自绘控件

小结

自定义view的内容到这里就结束了,相信对于简单的自定义view大家都可以简单的应对了。当然学习是无止境的,希望大家可以不断地探索学习,其中还有很多东西值得大家学习。下一期我想和大家分享的是:深度探索Activity!

原文链接:
[http://www.jianshu.com/p/61d338b30c4d)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 196,165评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,503评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,295评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,589评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,439评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,342评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,749评论 3 387
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,397评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,700评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,740评论 2 313
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,523评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,364评论 3 314
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,755评论 3 300
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,024评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,297评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,721评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,918评论 2 336

推荐阅读更多精彩内容