1. 程式人生 > >Android進階——自定義View之繼承TextView巧用DrawableLeft實現自己的CheckableTextView

Android進階——自定義View之繼承TextView巧用DrawableLeft實現自己的CheckableTextView

引言

Android自帶的許多控制元件已經十分強大,甚至很多功能都已經有現成的控制元件去使用了,不過介面效果是肯定會打折扣的,幸好android控制元件自身的擴充套件性十分優秀,很多時候我們只需要簡單繼承下現有控制元件擴充套件些許功能就能得到一個全新的控制元件,比如說前面Android進階——自定義View之繼承系統控制元件實現自帶刪除按鈕動畫效果和軟鍵盤自動懸浮於文字框下方 的核心思想就是如此。

一、自定義CheckableItemView概述

之前的專案中曾經使用過單選列表Android進階——RecycleView的使用之自定義單選列表(二) ,當時由於使用單選列表的業務不多,沒有使用自定義的View去實現,最近新專案中又使用了單選和多選列表,而且還比較頻繁,有必要封裝下,於是就自定義了一個選項Item,支援單選和多選。效果如圖:
這裡寫圖片描述

二、Android繼承系統控制元件實現自定義View的通用步驟

  • 繼承系統自帶控制元件並實現相應的構造方法

一般實現這三種即可

    public CheckedableItemView(Context context) {
        super(context);
        this.context=context;
    }

    public CheckedableItemView(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.context=context;
        init(attrs);
    }

    public
CheckedableItemView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); this.context=context; init(attrs); }
  • 自定義屬性
  • 構造方法中完成額外的初始化工作,一般包括獲取自定義屬性的值並初始化到控制元件上(只有初始化到控制元件之後我們定義的屬性才真正的發揮作用)、設定一些常見的屬性等
  • 完成功能邏輯的處理,比如說你要去實現勾選效果
  • 覆寫自帶的互動方法
  • 提供人機互動回撥介面

一句話概括其根本思想就是繼承系統控制元件的通用功能,通過去重寫構造方法或者其他方法去改變其邏輯,從而實現擴充套件功能

二、自定義CheckableItemView設計思想

1、繪製勾選框

TextView本身就自帶drawableLeft、drawableRight、drawableTop、drawableRight屬性可以在TextView的左右上下繪製對應的drawable,再設定下padding值即可,設定drawble之前一定要記得setBounds否則無法顯示。

    private void setRightIcon(){

        if(isChecked) {
            rightCheckedIcon.setBounds(0, 0, 68, 68);//一定要記得先設定setBounds,這裡我設定為68*68
            setCompoundDrawables(getCompoundDrawables()[0],
                    getCompoundDrawables()[1], rightCheckedIcon, getCompoundDrawables()[3]);
        }else {
            rightIcon.setBounds(0, 0, 68, 68);
            setCompoundDrawables(getCompoundDrawables()[0],
                    getCompoundDrawables()[1], rightIcon, getCompoundDrawables()[3]);
        }
    }

2、模擬勾選前和勾選後的效果

這裡我用的是兩套UI來簡單實現UI效果,但是我們TextView 本身並沒有提供類似Checked方法,這裡我是使用重寫onTouchEvent方法來實現的,但是重寫了onTouchEvent這個方法是針對整個TextView的,所以我這裡自己處理了下僅僅在Touch在勾選框區域才會去處理,此處需要注意OnTouch事件的傳遞機制,只有在 MotionEvent.ACTION_DOWN 返回為true時,才會繼續產生MotionEvent.ACTION_MOVE、UP事件

    /**
     * 模擬點選事件當我們按下的位置 在  TextView的寬度 - 圖示到控制元件右邊的間距 - 圖示的寬度  和
     * TextView的寬度 - 圖示到控制元件右邊的間距之間就相當於點選了右邊的Icon
     */
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
                return true;//只有在 MotionEvent.ACTION_DOWN 返回為true時,才會繼續產生MotionEvent.ACTION_MOVE/UP事件,
            case MotionEvent.ACTION_UP:
                if (getCompoundDrawables()[2] != null) {

                    boolean isRightClick = event.getX() > (getWidth() - getTotalPaddingRight())
                            && (event.getX() < ((getWidth() - getPaddingRight())));
                    if (isRightClick) {
                        if(isCheckedable) {
                            doChecked();
                        }
                    }
                }
            default:
                break;
        }

        return super.onTouchEvent(event);
    }

四、自定義CheckableItemView的實現

1、自定義屬性

 <declare-styleable name="checkedable_view">
 <!--format="reference" 即表示這個屬性對應的值是引用類似R.drawable.xx這樣的-->
        <attr name="rightIcon" format="reference"></attr>
        <attr name="rightCheckedIcon" format="reference"></attr>
        <attr name="isChecked" format="boolean"></attr>
        <attr name="modeType" format="integer"></attr>
    </declare-styleable>

2、CheckableItemView.java

package crazy.com.customview.widget;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.TextView;

import crazy.com.customview.R;

/**
 * auther: Crazy.Mo
 * Date: 2017/3/30
 * Time:10:09
 * Des:
 */

public class CheckedableItemView extends TextView {

    private Context context;
    private int modeType;//預設單選0,多選 1
    private boolean isCheckedable=true;
    private boolean isChecked=false;
    private int rightIconId;
    private Drawable rightIcon;//未選中
    private Drawable rightCheckedIcon;//選中

    public CheckedableItemView(Context context) {
        super(context);
        this.context=context;
    }

    public CheckedableItemView(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.context=context;
        init(attrs);
    }

    public CheckedableItemView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.context=context;
        init(attrs);
    }
    private void init(AttributeSet attrs){
        initAttrs(attrs);
        setRightIcon();
    }

    private void initAttrs(AttributeSet attrs){
        TypedArray types = context.obtainStyledAttributes(attrs,
                R.styleable.checkedable_view);
        try {
            modeType = types.getInt( R.styleable.checkedable_view_modeType,0 );
            isCheckedable = types.getBoolean( R.styleable.checkedable_view_isChecked,true );
            rightIcon=types.getDrawable(R.styleable.checkedable_view_rightIcon);
            rightCheckedIcon=types.getDrawable(R.styleable.checkedable_view_rightCheckedIcon);
        } finally {
            types.recycle(); // TypeArray用完需要recycle
        }
    }

    public boolean isCheckedable() {
        return isCheckedable;
    }

    public void setCheckedable(boolean checkedable) {
        isCheckedable = checkedable;
    }

    public boolean isChecked() {
        return isChecked;
    }

    public void setChecked(boolean checked) {
        isChecked = checked;
    }

    private void setRightIcon(){

        if(isChecked) {
            rightCheckedIcon.setBounds(0, 0, 68, 68);
            setCompoundDrawables(getCompoundDrawables()[0],
                    getCompoundDrawables()[1], rightCheckedIcon, getCompoundDrawables()[3]);
        }else {
            rightIcon.setBounds(0, 0, 68, 68);
            setCompoundDrawables(getCompoundDrawables()[0],
                    getCompoundDrawables()[1], rightIcon, getCompoundDrawables()[3]);
        }
    }

    /**
     * 模擬點選事件當我們按下的位置 在  TextView的寬度 - 圖示到控制元件右邊的間距 - 圖示的寬度  和
     * TextView的寬度 - 圖示到控制元件右邊的間距之間就相當於點選了右邊的Icon
     */
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
                return true;//只有在 MotionEvent.ACTION_DOWN 返回為true時,才會繼續產生MotionEvent.ACTION_MOVE/UP事件,
            case MotionEvent.ACTION_UP:
                if (getCompoundDrawables()[2] != null) {

                    boolean isRightClick = event.getX() > (getWidth() - getTotalPaddingRight())
                            && (event.getX() < ((getWidth() - getPaddingRight())));
                    if (isRightClick) {
                        if(isCheckedable) {
                            doChecked();
                        }
                    }
                }
            default:
                break;
        }

        return super.onTouchEvent(event);
    }

    private void doChecked(){
        if(isChecked){
            rightIcon.setBounds(0, 0, 68, 68);
            setCompoundDrawables(getCompoundDrawables()[0],getCompoundDrawables()[1], rightIcon, getCompoundDrawables()[3]);
            isChecked=false;
        }else {
            rightCheckedIcon.setBounds(0, 0, 68, 68);
            setCompoundDrawables(getCompoundDrawables()[0], getCompoundDrawables()[1], rightCheckedIcon, getCompoundDrawables()[3]);
            isChecked=true;
        }
    }
}

3、使用

shape_edit_found.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">

        <!-- 定義邊框線 -->
        <stroke android:width="0.3dp" android:color="#6bb9a9" />

        <!-- 定義圓角(圓角半徑是4.5dp) -->
        <corners android:radius="4.5dp" />

        <!-- 背景色 -->
        <solid android:color="#ffffff" />

</shape>

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:crazymo="http://schemas.android.com/apk/res-auto"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="crazy.com.customview.MainActivity">

    <crazy.com.customview.widget.CheckedableItemView
        android:id="@+id/single_checked"
        android:gravity="center|left"
        android:layout_marginTop="6dp"
        android:layout_marginLeft="10dp"
        android:layout_marginRight="10dp"
        android:paddingLeft="6dp"
        android:paddingRight="6dp"
        android:layout_width="match_parent"
        android:layout_height="56dp"
        android:background="@drawable/shape_edit_found"
        android:text="你的性別是?"
        android:textSize="26sp"
        crazymo:modeType="0"
        crazymo:rightIcon="@mipmap/single"
        crazymo:rightCheckedIcon="@mipmap/single_selected"/>

    <crazy.com.customview.widget.CheckedableItemView
        android:id="@+id/multi_checked"
        android:gravity="center|left"
        android:paddingLeft="6dp"
        android:paddingRight="6dp"
        android:layout_marginLeft="10dp"
        android:layout_marginRight="10dp"
        android:layout_width="match_parent"
        android:layout_height="56dp"
        android:background="@drawable/shape_edit_found"
        android:layout_below="@id/single_checked"
        android:text="你喜歡的運動?"
        android:textSize="26sp"
        crazymo:modeType="1"
        crazymo:rightIcon="@mipmap/multi"
        crazymo:rightCheckedIcon="@mipmap/multi_selected"/>
</RelativeLayout>

這個控制元件主要就是分享一種思想,靈活的借用系統自帶的功能去擴充套件自己的控制元件,靈活地封裝會減少很多不必要工作。原始碼直通車

相關推薦

Android——定義View繼承TextViewDrawableLeft實現自己CheckableTextView

引言 Android自帶的許多控制元件已經十分強大,甚至很多功能都已經有現成的控制元件去使用了,不過介面效果是肯定會打折扣的,幸好android控制元件自身的擴充套件性十分優秀,很多時候我們只需要簡單繼承下現有控制元件擴充套件些許功能就能得到一個全新的控制元件

Android——定義View擴充套件系統控制元件的另一種思路實現漸變文字動畫的TextView

引言 前面幾篇文章 繼承或組合系統現有控制元件實現新控制元件,擴充套件新功能都是在對應的構造方法中去擴充套件的,但千萬不要把思路侷限於只能在構造方法中去擴充套件,這篇就簡單地分享另一種思路,通過重寫對應的週期方法實現擴充套件。 一、View中幾種重

Android——定義ViewView的繪製流程及實現onMeasure完全攻略

引言 Android實際專案開發中,自定義View不可或缺,而作為自定義View的一種重要實現方式——繼承View重繪尤其重要,前面很多文章基本總結了繼承View的基本流程:自定義屬性和繼承View重寫onDraw方法——>實現構造方法並完成相關初始化操

Android——定義View組合系統控制元件實現水珠形狀的ItemView

引言 相信大家在專案開發的過程中一定會有不少需要在上方顯示一張圖片,而在其下方顯示提示標題的效果,作為一個介面的功能按鈕或者單純作為一個列表的item項,尤其是當這個item還需要顯示一些動畫效果時候,此時更應該當成一個整體,否則動畫效果就會需要額外的調整,否

HenCoder Android 開發: 定義 View 1-1 繪製基礎

自定義繪製概述 二話不說,我反手就是一個視訊:(視訊掛了,先直接點到優酷去看吧:優酷連結) 首先總結一下視訊中的關鍵點: 自定義繪製的方式是重寫繪製方法,其中最常用的是 onDraw() 繪製的關鍵是 Canvas 的使用 Canvas 的繪製類方法: drawXX

Android開發——定義View的使用及其原理探索

  在Android開發中,系統提供給我們的UI控制元件是有限的,當我們需要使用一些特殊的控制元件的時候,只靠系統提供的控制元件,可能無法達到我們想要的效果,這時,就需要我們自定義一些控制元件,來完成我們想要的效果了。下面,我就來講講自定義控制元件的那些事。   首先,我來講講Android的控制元件架構。

Android繪圖:定義View——矩形進度條、圓環進度條、填充型進度條、時鐘

主函式 這幾種進度條的主函式都是類似的,所以下面我只給出了一個填充型進度條的主函式,其他幾個主函式只是在這基礎上改動一下按鈕id(即與各自佈局裡面的id相同即可),還有改動一下相對應的類即可。 public class MainActivity

Android定義View仿QQ側滑選單實現

最近,由於正在做的一個應用中要用到側滑選單,所以通過查資料看視訊,學習了一下自定義View,實現一個類似於QQ的側滑選單,順便還將其封裝為自定義元件,可以實現類似QQ的側滑選單和抽屜式側滑選單兩種選單。 下面先放上效果圖: 我們這裡的側

android學習5#--定義View座標系統

近期在學習android過程中,看到有人在伯樂在線上分享如何開發自定義View的一系列文章。我覺得對於初學者,很有必要掌握它,因為今後很多時候系統自帶的元件不足以滿足我們的功能需求,那麼我們就要根據需求來定義一個能滿足我們需求的View元件。 但是我並不會按照

定義View繼承LinearLayout

自定義View有三種方式: 1:完全自定義View,也就是繼承View,或者ViewGroup還有就是SurfaceView 2:半自定義View,所謂半自定View就是繼承SDK中已經寫好的一些View,比如LinearLayout、RelativeLayout、Frag

Android定義 view圖片裁剪從設計到實現

android圖片剪下是常用的功能,因為部落格開發的是SDK不涉及到activity,所以就需要自定義裁剪功能,參閱了網上的大部分資料後,在github上一個封裝好的裁剪庫cropper,正好符合要求,本著拿來主義的思想,直接把原始碼clone嵌入到專案裡,然後

Android 定義 ViewGroup 定義佈局

前言 在我們的實際應用中, 經常需要用到自定義控制元件,比如自定義圓形頭像,自定義計步器等等。但有時我們不僅需要自定義控制元件,舉個例子,FloatingActionButton 大家都很常用,所以大家也很經常會有一種需求,點選某個 FloatingActionButton 彈出更多 FloatingActi

定義View圓形TextView

【1】自定義View的屬性 :   在res/values下新建一個attrs.xml檔案,在裡面定義我們的屬性 <?xml version="1.0" encoding="utf-8"?> <resources> <at

Android系列:八、定義View音頻抖動動效

final rim 而是 開始 next draw img 點擊 syn 自定義動畫效果——音頻抖動效果 1.繪制一個矩形: 想要繪制一個矩形,繼承View,並重寫onDraw方法即可。復雜一點還可以重寫onMeasure方法和onLayout方法進行大小測量和位置測量。但

Android:九、定義View手寫Loading動效

應該 ima outer list 初始 ffffff tar implement 旋轉角度 這是一個很簡單的動畫效果,使用屬性動畫即可實現,希望對讀者學習動畫能達到拋磚引玉的效果 一.自定義動畫效果——Loading效果 如上是我們需要做的一個Loading動畫。Loa

Android定義View分貝儀

一、說明        最近在整理自定義View方面的知識,偶爾看到meizu工具箱的分貝儀效果,感覺它的實效效果還挺好的,遂想自己模擬實現練練手,廢話不多說,直接開擼。 二、效果圖 首先看一下效果圖: 看效果還挺炫酷

Android定義ViewCanvas

https://www.jianshu.com/p/fb18c28d6627 用繼承View的方式來自定義View,我們就需要重寫onDraw方法,也就是得咱自己來畫圖了。畫圖就得用到畫筆和畫布,也就是Paint和Canvas。我們來了解下Canvas。 Canvas Canvas我們可

Android 定義ViewCanvas詳解

自定義View的相關文章: Android 實現一個簡單的自定義View Android 自定義View步驟 Android Paint詳解 Android 自定義View之Canvas相關方法說明 Android 自定義View例項之 “京東跑”

Android輸入框自動提示--定義佈局

發現Android的有兩種方法AutoCompleteTextView和MultiAutoCompleteTextView提示出來的提示框只是純文字而且是單條資料,要是想實現加一個圖片或者是每一條資料展示兩個資料呢,這就需要重寫介面卡設定佈局了 重寫介面卡: packag

Android : 定義View流式佈局

寫了一個很簡單的佈局 這是周圍圓框的drawable <?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android">