Android自定義控件實(shí)現(xiàn)簡單寫字板功能
先來看看效果圖

就是簡單的根據(jù)手指寫下的軌跡去畫出內(nèi)容
一、實(shí)現(xiàn)
之前一篇文章里提到了android官方給出的自定義控件需要考慮以下幾點(diǎn):
創(chuàng)建View
處理View的布局
繪制View
與用戶進(jìn)行交互
優(yōu)化已定義的View
就按照這個(gè)步驟來完成今天的自定義控件
1、創(chuàng)建View
上篇提到創(chuàng)建View這一步的時(shí)候要考慮的就是很簡單的自定義屬性的聲明、使用。
今天的控件可以有一些什么自定義屬性呢?要實(shí)現(xiàn)寫字板,其實(shí)就是三個(gè)東西:寫字板的顏色、筆的顏色、筆的粗細(xì)。所以接下來自定義屬性。
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="WritingBoardView">
<attr name="boardBackground" format="color"></attr> <!--畫板顏色-->
<attr name="paintColor" format="color"></attr> <!--畫筆顏色-->
<attr name="paintWidth" format="dimension"></attr> <!--畫筆寬度-->
</declare-styleable>
</resources>
定義了就是為了要使用
<?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"
xmlns:custom="http://schemas.android.com/apk/res-auto"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.qiangyu.test.writingboardview.MainActivity">
<com.qiangyu.test.writingboardview.view.WritingBoardView
android:layout_width="match_parent"
android:layout_height="match_parent"
custom:paintColor="@color/colorAccent"
custom:boardBackground="@color/colorPrimary"
custom:paintWidth="3dp"/>
</RelativeLayout>
簡單的設(shè)置了boardBackground、paintWidth和paintColor屬性
使用這里只需要注意命名空間,android提供給我們的用android,我們可以自定義我們屬性的命名空間
寫法為:xmlns:你取的名=”http://schemas.android.com/apk/res-auto”,這里的res-auto可以換成你控件的包名
在XML布局文件中設(shè)置的屬性要在自定義屬性中獲取到,所以我們必須實(shí)現(xiàn)帶有Context, AttributeSet的構(gòu)造方法
private int mBoardBackground;//畫板顏色
private int mPaintColor;//畫筆顏色
private int mPaintWidth;//畫筆寬度
private Path mPath;
private Paint mPaint;//畫筆
public WritingBoardView(Context context) {
this(context,null);
}
public WritingBoardView(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public WritingBoardView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context,attrs);
}
private void init(Context context,AttributeSet attrs) {
TypedArray a = context.obtainStyledAttributes(attrs,R.styleable.WritingBoardView);
mBoardBackground = a.getColor(R.styleable.WritingBoardView_boardBackground,Color.WHITE);
mPaintColor = a.getColor(R.styleable.WritingBoardView_paintColor,Color.BLUE);
mPaintWidth = a.getDimensionPixelSize(R.styleable.WritingBoardView_paintWidth,
(int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,5,getResources().getDisplayMetrics()));
a.recycle();
mPaint = new Paint();
mPath = new Path();
setBackgroundColor(mBoardBackground);
mPaint.setColor(mPaintColor);
mPaint.setStrokeWidth(mPaintWidth);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setAntiAlias(true);
}
上面代碼確保了每個(gè)構(gòu)造方法最終都調(diào)用了第三個(gè)構(gòu)造方法里的init(context,attrs) 方法來獲取自定義屬性和初始化一些信息
通過固定的寫法、簡單的獲取到自定義屬性,并且給當(dāng)前view設(shè)置背景、為Paint設(shè)置了樣式和顏色。完成寫字板很重要的就是這里的Path類。
先來介紹一下Path類
看構(gòu)造方法的注釋
/**
* The Path class encapsulates compound (multiple contour) geometric paths
* consisting of straight line segments, quadratic curves, and cubic curves.
* It can be drawn with canvas.drawPath(path, paint), either filled or stroked
* (based on the paint's Style), or it can be used for clipping or to draw
* text on a path.
*/
public class Path {
...
}
大體就是說Path封裝了由了直線和各種曲線組成幾何圖形信息。我們可以調(diào)用canvas通過drawPath方法來畫一些東西。
我們最終的draw就是需要用到drawPath
Path里包含了很多設(shè)置幾何圖形的方法如addRect、addArc。
今天重點(diǎn)說用到的兩個(gè)方法:
/**
* Set the beginning of the next contour to the point (x,y).
*
* @param x The x-coordinate of the start of a new contour
* @param y The y-coordinate of the start of a new contour
*/
public void moveTo(float x, float y) {
native_moveTo(mNativePath, x, y);
}
moveTo方法就是設(shè)置下一個(gè)連線或者圖形最開始的位置。
/**
* Add a line from the last point to the specified point (x,y).
* If no moveTo() call has been made for this contour, the first point is
* automatically set to (0,0).
*
* @param x The x-coordinate of the end of a line
* @param y The y-coordinate of the end of a line
*/
public void lineTo(float x, float y) {
isSimplePath = false;
native_lineTo(mNativePath, x, y);
}
lineTo方法簡單的添加一條上一個(gè)點(diǎn)到當(dāng)前點(diǎn)的線。
有了這兩個(gè)方法我們就可以實(shí)線寫字板了
2、處理View的布局
由于這個(gè)自定義控件本身就需要一塊內(nèi)容當(dāng)寫字板,所以就不用特別的布局處理了,只是在mode為UNSPECIFIED的時(shí)候可能會(huì)導(dǎo)致布局顯示不出來。
在這里就不進(jìn)行特殊處理了。
3、繪制View、與用戶進(jìn)行交互
由于該控件本身就需要交互才產(chǎn)生效果,所以之前的兩步放在一起考慮了。
上面說到過Canvas有一個(gè)drawPath方法。drawPath最后繪制出來什么樣其實(shí)是看Path里包含的信息。
我們要實(shí)現(xiàn)實(shí)時(shí)顯示手寫的內(nèi)容,只需要在滑動(dòng)的時(shí)候獲取的坐標(biāo)通過Path的lineTo方法將線一點(diǎn)一點(diǎn)的連起來。
當(dāng)手指抬起再落下的時(shí)候應(yīng)該又是一條新的線,所以在落下的時(shí)候我們需要調(diào)用moveTo方法來為下一條軌跡設(shè)置一個(gè)起點(diǎn)。
@Override
public boolean onTouchEvent(MotionEvent event) {
float touchX = event.getX();
float touchY = event.getY();
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
mPath.moveTo(touchX,touchY);//重新設(shè)置即將出現(xiàn)的線的起點(diǎn)
break;
case MotionEvent.ACTION_MOVE:
mPath.lineTo(touchX,touchY);//連線
break;
case MotionEvent.ACTION_UP:
break;
}
invalidate();//通知系統(tǒng)重繪
return true;//要處理當(dāng)前事件
}
在onTouch中return true表示要處理當(dāng)前事件。并且在每一次操作調(diào)用invalidate來繪制界面,我們的onDraw 方法只需要簡單的調(diào)用drawPath就可以了
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawPath(mPath,mPaint);
}
總結(jié)
其實(shí)就是通過手指的觸摸事件來控制軌跡的改變,按照固定的模式,一個(gè)簡單的自定義控件就大功告成啦!
一個(gè)簡單的寫字板就基本完成了,當(dāng)然你感興趣可以擴(kuò)展一下,加上在運(yùn)行時(shí)改變畫筆的顏色、畫板的顏色。添加字體擦除去的功能。
相關(guān)文章
Android View移動(dòng)的六種方法小結(jié)
在android開發(fā)中,經(jīng)常會(huì)遇到一個(gè)view需要它能夠支持滑動(dòng)的需求。下面通過本篇文章給大家介紹android view移動(dòng)的六種方法,對android view移動(dòng)相關(guān)知識(shí)感興趣的朋友一起學(xué)習(xí)吧2015-12-12
Android實(shí)現(xiàn)漸變啟動(dòng)頁和帶有指示器的引導(dǎo)頁
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)漸變啟動(dòng)頁和帶有指示器的引導(dǎo)頁,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-09-09
支付寶咻一咻怎么用 Android幫你實(shí)現(xiàn)咻一咻
Android幫你實(shí)現(xiàn)咻一咻,這篇文章主要為大家介紹了支付寶咻一咻的幾種思路,感興趣的朋友可以參考一下2016-02-02
ExpandableListView實(shí)現(xiàn)簡單二級列表
這篇文章主要為大家詳細(xì)介紹了ExpandableListView實(shí)現(xiàn)簡單二級列表,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-11-11
Android SDK命令行工具M(jìn)onkey參數(shù)及使用解析
這篇文章主要介紹了Android SDK命令行工具M(jìn)onkey參,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值數(shù)及使用解析,需要的朋友可以參考下2020-10-10
Android BottomNavigationView與Fragment重建與重疊問題解決方法探索
這篇文章主要介紹了Android BottomNavigationView與Fragment重建與重疊問題解決,總的來說這并不是一道難題,那為什么要拿出這道題介紹?拿出這道題真正想要傳達(dá)的是解題的思路,以及不斷優(yōu)化探尋最優(yōu)解的過程。希望通過這道題能給你帶來一種解題優(yōu)化的思路2023-01-01

