自定義控件的三種方式

文章轉(zhuǎn)載于https://blog.csdn.net/fictionss/article/details/78285167

原生控件,自己繪制和繼承原生控件.

1.組合原生控件

將自己需要的控件組合起來變成一個新控件,如下制作常見的app頁面頭部.

?新建一個Android項目,創(chuàng)建一個頭部布局view_top.xml

android:layout_width="match_parent"??

android:layout_height="wrap_content"??

android:orientation="vertical"??

android:background="#50e7ab"??

android:padding="10dp"> ?

android:id="@+id/top_left"??

android:layout_width="wrap_content"??

android:layout_height="wrap_content"??

android:src="@mipmap/fanhui_bai"?/> ?

android:id="@+id/top_title"??

android:layout_width="wrap_content"??

android:layout_height="wrap_content"??

android:layout_centerHorizontal="true"RelativeLayout???

android:layout_centerVertical="true"??

android:text="首頁"??

android:textSize="17sp"??

android:textColor="#ffffff"?/> ?

android:id="@+id/top_right"??

android:layout_width="wrap_content"??

android:layout_height="wrap_content"??

android:text="提交"??

android:textSize="17sp"??

android:textColor="#ffffff"??

android:layout_centerVertical="true"??

android:layout_alignParentRight="true"?/> ?

下面創(chuàng)建一個TopView繼承RelativeLayout

package?t.s.com; ?

import?android.content.Context;??

import?android.util.AttributeSet;??

import?android.view.LayoutInflater;??

import?android.widget.ImageView;??

import?android.widget.RelativeLayout;??

import?android.widget.TextView; ?

/**

?*?Created?by?Administrator?on?2017/10/19.

?*/ ?

public?class?TopView?extends?RelativeLayout?{??

//?返回按鈕控件??

private?ImageView?top_left;??

//?標(biāo)題Tv??

private?TextView?top_title; ?

private?TextView?top_right; ?

public?TopView(Context?context)?{??

super(context);??

????} ?

public?TopView(Context?context,?AttributeSet?attrs)?{??

super(context,?attrs);??

//?加載布局??

LayoutInflater.from(context).inflate(R.layout.view_top,this);??

//?獲取控件??

????????top_left?=?(ImageView)?findViewById(R.id.top_left);??

????????top_title?=?(TextView)?findViewById(R.id.top_title);??

????????top_right?=?(TextView)?findViewById(R.id.top_right);??

????} ?

//?為左側(cè)返回按鈕添加自定義點擊事件??

public?void?setOnclickLeft(OnClickListener?listener)?{??

????????top_left.setOnClickListener(listener);??

????} ?

//?設(shè)置標(biāo)題的方法??

public?void?setTitle(String?title)?{??

????????top_title.setText(title);??

????} ?

//?設(shè)置標(biāo)題的方法??

public?void?setRightTitle(String?title)?{??

????????top_right.setText(title);??

????} ?

}??

然后在activity_main.xml中引用

xmlns:app="http://schemas.android.com/apk/res-auto"??

xmlns:tools="http://schemas.android.com/tools"??

android:layout_width="match_parent"??

android:layout_height="match_parent"??

tools:context="t.s.com.MainActivity"> ?

android:id="@+id/top_view"??

android:layout_width="match_parent"??

android:layout_height="wrap_content"?/> ?

然后再在MainActivity中對控件做操作

package?t.s.com; ?

import?android.support.v7.app.AppCompatActivity;??

import?android.os.Bundle;??

import?android.view.View;??

import?android.widget.Toast; ?

public?class?MainActivity?extends?AppCompatActivity?{??

private?TopView?topView; ?


@Override??

protected?void?onCreate(Bundle?savedInstanceState)?{??

super.onCreate(savedInstanceState);??

????????setContentView(R.layout.activity_main);??

????????topView?=?(TopView)?findViewById(R.id.top_view);??


topView.setOnclickLeft(new?View.OnClickListener()?{??

@Override??

public?void?onClick(View?view)?{??

Toast.makeText(MainActivity.this,?"點擊了返回按鈕",?Toast.LENGTH_SHORT).show();??

????????????}??

????????});??

topView.setRightTitle("設(shè)置");??

topView.setTitle("首頁");??

????}??

}??

運行效果

2.自己繪制控件

熟悉view的繪制原理

1.measure用來測量View的寬和高。?

2.layout用來確定View在父容器中放置的位置劝评。?

3.draw用來將view繪制在屏幕上

創(chuàng)建一個類CustomView繼承View咒唆,實現(xiàn)點擊事件接口OnClickListener

package?t.s.com;??


import?android.content.Context;??

import?android.graphics.Canvas;??

import?android.graphics.Color;??

import?android.graphics.Paint;??

import?android.graphics.Rect;??

import?android.util.AttributeSet;??

import?android.view.View;??


/**

?*?Created?by?Administrator?on?2017/10/19.

?*/??


public?class?CustomView?extends?View?implements?View.OnClickListener?{??


//?定義畫筆??

private?Paint?mPaint;??

//?用于獲取文字的寬和高??

private?Rect?mRect;??

//?計數(shù)值步势,每點擊一次本控件,其值增加1??

private?int?mCount=0;??


public?CustomView(Context?context,?AttributeSet?attrs)?{??

super(context,?attrs);??


//?初始化畫筆逆巍、Rect??

mPaint?=new?Paint(Paint.ANTI_ALIAS_FLAG);??

mRect?=new?Rect();??

//?本控件的點擊事件??

setOnClickListener(this);??

????}??


@Override??

protected?void?onDraw(Canvas?canvas)?{??

super.onDraw(canvas);??

????????mPaint.setColor(Color.BLACK);??

//?繪制一個填充色為藍色的矩形??

canvas.drawRect(0,?0,?getWidth(),?getHeight(),?mPaint);??

????????mPaint.setColor(Color.WHITE);??

mPaint.setTextSize(50);??

????????String?text?=?String.valueOf(mCount);??

//?獲取文字的寬和高??

mPaint.getTextBounds(text,0,?text.length(),?mRect);??

float?textWidth?=?mRect.width();??

float?textHeight?=?mRect.height();??


//?繪制字符串??

canvas.drawText("點了我"+text+"次",?getWidth()?/?2?-?textWidth?/?2,?getHeight()?/?2??

+?textHeight?/2,?mPaint);??

????}??


@Override??

public?void?onClick(View?view)?{??

????????mCount++;??

????????invalidate();??

????}??

}??

在activity_main.xml中引入該自定義布局:

[java]?view plain?copy


xmlns:app="http://schemas.android.com/apk/res-auto"??

xmlns:tools="http://schemas.android.com/tools"??

android:layout_width="match_parent"??

android:layout_height="match_parent"??

android:orientation="vertical"??

tools:context="t.s.com.MainActivity">??



android:id="@+id/top_view"??

android:layout_width="match_parent"??

android:layout_height="wrap_content"?/>??




android:id="@+id/custom"??

android:layout_width="300dp"??

android:layout_height="200dp"??

android:layout_gravity="center"/>??




運行效果圖

當(dāng)然這個自定義控件比較粗糙,實際的要根據(jù)業(yè)務(wù)需求邏輯自己繪制,原理一樣.

3.繼承原生控件? 下面以一個不允許輸入表情的EditText作為例子

package?t.s.com;??

import?android.annotation.SuppressLint;??

import?android.content.Context;??

import?android.text.Editable;??

import?android.text.Selection;??

import?android.text.Spannable;??

import?android.text.TextWatcher;??

import?android.util.AttributeSet;??

import?android.widget.EditText;??

import?android.widget.Toast;??


/**

?*?Created?by?Administrator?on?2017/6/5?0005.

?*/??


@SuppressLint("AppCompatCustomView")??

public?class?EmoEditText?extends?EditText?{??

//輸入表情前的光標(biāo)位置??

private?int?cursorPos;??

//輸入表情前EditText中的文本??

private?String?inputAfterText;??

//是否重置了EditText的內(nèi)容??

private?boolean?resetText;??


private?Context?mContext;??


public?EmoEditText(Context?context)?{??

super(context);??

this.mContext?=?context;??

????????initEditText();??

????}??


public?EmoEditText(Context?context,?AttributeSet?attrs)?{??

super(context,?attrs);??

this.mContext?=?context;??

????????initEditText();??

????}??


public?EmoEditText(Context?context,?AttributeSet?attrs,?int?defStyleAttr)?{??

super(context,?attrs,?defStyleAttr);??

this.mContext?=?context;??

????????initEditText();??

????}??


//?初始化edittext?控件??

private?void?initEditText()?{??

addTextChangedListener(new?TextWatcher()?{??

@Override??

public?void?beforeTextChanged(CharSequence?s,?int?start,?int?before,?int?count)?{??

if?(!resetText)?{??

????????????????????cursorPos?=?getSelectionEnd();??

//?這里用s.toString()而不直接用s是因為如果用s省容,??

//?那么,inputAfterText和s在內(nèi)存中指向的是同一個地址痪寻,s改變了,??

//?inputAfterText也就改變了虽惭,那么表情過濾就失敗了??

????????????????????inputAfterText=?s.toString();??

????????????????}??

????????????}??


@Override??

public?void?onTextChanged(CharSequence?s,?int?start,?int?before,?int?count)?{??

if?(!resetText)?{??

if?(count?>=?2)?{//表情符號的字符長度最小為2??

????????????????????????CharSequence?input?=?s.subSequence(cursorPos,?cursorPos?+?count);??

if?(containsEmoji(input.toString()))?{??

resetText?=true;??

Toast.makeText(mContext,"暫不支持表情評論哦",?Toast.LENGTH_SHORT).show();??

//是表情符號就將文本還原為輸入表情符號之前的內(nèi)容??

????????????????????????????setText(inputAfterText);??

????????????????????????????CharSequence?text?=?getText();??

if?(text?instanceof?Spannable)?{??

????????????????????????????????Spannable?spanText?=?(Spannable)?text;??

????????????????????????????????Selection.setSelection(spanText,?text.length());??

????????????????????????????}??

????????????????????????}??

????????????????????}??

}else?{??

resetText?=false;??

????????????????}??

????????????}??


@Override??

public?void?afterTextChanged(Editable?editable)?{??


????????????}??

????????});??

????}??



/**

?????*?檢測是否有emoji表情

?????*

?????*?@param?source

?????*?@return

?????*/??

public?static?boolean?containsEmoji(String?source)?{??

int?len?=?source.length();??

for?(int?i?=?0;?i?<?len;?i++)?{??

char?codePoint?=?source.charAt(i);??

if?(!isEmojiCharacter(codePoint))?{?//如果不能匹配,則該字符是Emoji表情??

return?true;??

????????????}??

????????}??

return?false;??

????}??


/**

?????*?判斷是否是Emoji

?????*

?????*?@param?codePoint?比較的單個字符

?????*?@return

?????*/??

private?static?boolean?isEmojiCharacter(char?codePoint)?{??

return?(codePoint?==?0x0)?||?(codePoint?==?0x9)?||?(codePoint?==?0xA)?||??

(codePoint?==0xD)?||?((codePoint?>=?0x20)?&&?(codePoint?<=?0xD7FF))?||??

((codePoint?>=0xE000)?&&?(codePoint?<=?0xFFFD))?||?((codePoint?>=?0x10000)??

&&?(codePoint?<=0x10FFFF));??

????}??

}??

然后在activity_main.xml引入該控件就可以了

android:id="@+id/edtext"??

android:layout_width="match_parent"??

android:layout_height="wrap_content"?/>??

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末橡类,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子芽唇,更是在濱河造成了極大的恐慌顾画,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,080評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異亲雪,居然都是意外死亡,警方通過查閱死者的電腦和手機疚膊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,422評論 3 385
  • 文/潘曉璐 我一進店門义辕,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人寓盗,你說我怎么就攤上這事灌砖。” “怎么了傀蚌?”我有些...
    開封第一講書人閱讀 157,630評論 0 348
  • 文/不壞的土叔 我叫張陵基显,是天一觀的道長。 經(jīng)常有香客問我善炫,道長撩幽,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,554評論 1 284
  • 正文 為了忘掉前任箩艺,我火速辦了婚禮窜醉,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘艺谆。我一直安慰自己榨惰,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,662評論 6 386
  • 文/花漫 我一把揭開白布静汤。 她就那樣靜靜地躺著琅催,像睡著了一般。 火紅的嫁衣襯著肌膚如雪虫给。 梳的紋絲不亂的頭發(fā)上藤抡,一...
    開封第一講書人閱讀 49,856評論 1 290
  • 那天,我揣著相機與錄音抹估,去河邊找鬼杰捂。 笑死,一個胖子當(dāng)著我的面吹牛棋蚌,可吹牛的內(nèi)容都是我干的嫁佳。 我是一名探鬼主播,決...
    沈念sama閱讀 39,014評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼谷暮,長吁一口氣:“原來是場噩夢啊……” “哼蒿往!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起湿弦,我...
    開封第一講書人閱讀 37,752評論 0 268
  • 序言:老撾萬榮一對情侶失蹤瓤漏,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蔬充,經(jīng)...
    沈念sama閱讀 44,212評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡蝶俱,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,541評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了饥漫。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片榨呆。...
    茶點故事閱讀 38,687評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖庸队,靈堂內(nèi)的尸體忽然破棺而出积蜻,到底是詐尸還是另有隱情,我是刑警寧澤彻消,帶...
    沈念sama閱讀 34,347評論 4 331
  • 正文 年R本政府宣布竿拆,位于F島的核電站,受9級特大地震影響宾尚,放射性物質(zhì)發(fā)生泄漏丙笋。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,973評論 3 315
  • 文/蒙蒙 一煌贴、第九天 我趴在偏房一處隱蔽的房頂上張望不见。 院中可真熱鬧,春花似錦崔步、人聲如沸稳吮。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,777評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽灶似。三九已至,卻和暖如春瑞你,著一層夾襖步出監(jiān)牢的瞬間酪惭,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,006評論 1 266
  • 我被黑心中介騙來泰國打工者甲, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留春感,地道東北人。 一個月前我還...
    沈念sama閱讀 46,406評論 2 360
  • 正文 我出身青樓虏缸,卻偏偏與公主長得像鲫懒,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子刽辙,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,576評論 2 349

推薦閱讀更多精彩內(nèi)容