文章轉(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"?/>??