開發(fā)自定義控件的步驟:
創(chuàng)新互聯(lián)主營石景山網(wǎng)站建設(shè)的網(wǎng)絡(luò)公司,主營網(wǎng)站建設(shè)方案,手機APP定制開發(fā),石景山h5微信小程序開發(fā)搭建,石景山網(wǎng)站營銷推廣歡迎石景山等地區(qū)企業(yè)咨詢
1、了解View的工作原理
2、 編寫繼承自View的子類
3、 為自定義View類增加屬性
4、 繪制控件
5、 響應(yīng)用戶消息
6 、自定義回調(diào)函數(shù)
一、View結(jié)構(gòu)原理
Android系統(tǒng)的視圖結(jié)構(gòu)的設(shè)計也采用了組合模式,即View作為所有圖形的基類,Viewgroup對View繼承擴展為視圖容器類。
View定義了繪圖的基本操作
基本操作由三個函數(shù)完成:measure()、layout()、draw(),其內(nèi)部又分別包含了onMeasure()、onLayout()、onDraw()三個子方法。具體操作如下:
1、measure操作
measure操作主要用于計算視圖的大小,即視圖的寬度和長度。在view中定義為final類型,要求子類不能修改。measure()函數(shù)中又會調(diào)用下面的函數(shù):
(1)onMeasure(),視圖大小的將在這里最終確定,也就是說measure只是對onMeasure的一個包裝,子類可以覆寫onMeasure()方法實現(xiàn)自己的計算視圖大小的方式,并通過setMeasuredDimension(width, height)保存計算結(jié)果。
2、layout操作
layout操作用于設(shè)置視圖在屏幕中顯示的位置。在view中定義為final類型,要求子類不能修改。layout()函數(shù)中有兩個基本操作:
(1)setFrame(l,t,r,b),l,t,r,b即子視圖在父視圖中的具體位置,該函數(shù)用于將這些參數(shù)保存起來;
(2)onLayout(),在View中這個函數(shù)什么都不會做,提供該函數(shù)主要是為viewGroup類型布局子視圖用的;
3、draw操作
draw操作利用前兩部得到的參數(shù),將視圖顯示在屏幕上,到這里也就完成了整個的視圖繪制工作。子類也不應(yīng)該修改該方法,因為其內(nèi)部定義了繪圖的基本操作:
(1)繪制背景;
(2)如果要視圖顯示漸變框,這里會做一些準備工作;
(3)繪制視圖本身,即調(diào)用onDraw()函數(shù)。在view中onDraw()是個空函數(shù),也就是說具體的視圖都要覆寫該函數(shù)來實現(xiàn)自己的顯示(比如TextView在這里實現(xiàn)了繪制文字的過程)。而對于ViewGroup則不需要實現(xiàn)該函數(shù),因為作為容器是“沒有內(nèi)容“的,其包含了多個子view,而子View已經(jīng)實現(xiàn)了自己的繪制方法,因此只需要告訴子view繪制自己就可以了,也就是下面的dispatchDraw()方法;
(4)繪制子視圖,即dispatchDraw()函數(shù)。在view中這是個空函數(shù),具體的視圖不需要實現(xiàn)該方法,它是專門為容器類準備的,也就是容器類必須實現(xiàn)該方法;
(5)如果需要(應(yīng)用程序調(diào)用了setVerticalFadingEdge或者setHorizontalFadingEdge),開始繪制漸變框;
(6)繪制滾動條;
從上面可以看出自定義View需要最少覆寫onMeasure()和onDraw()兩個方法。
二、View類的構(gòu)造方法
創(chuàng)建自定義控件的3種主要實現(xiàn)方式:
1)繼承已有的控件來實現(xiàn)自定義控件: 主要是當(dāng)要實現(xiàn)的控件和已有的控件在很多方面比較類似, 通過對已有控件的擴展來滿足要求。
2)通過繼承一個布局文件實現(xiàn)自定義控件,一般來說做組合控件時可以通過這個方式來實現(xiàn)。
注意此時不用onDraw方法,在構(gòu)造廣告中通過inflater加載自定義控件的布局文件,再addView(view),自定義控件的圖形界面就加載進來了。
3)通過繼承view類來實現(xiàn)自定義控件,使用GDI繪制出組件界面,一般無法通過上述兩種方式來實現(xiàn)時用該方式。
三、自定義View增加屬性的兩種方法:
1)在View類中定義。通過構(gòu)造函數(shù)中引入的AttributeSet 去查找XML布局的屬性名稱,然后找到它對應(yīng)引用的資源ID去找值。
案例:實現(xiàn)一個帶文字的圖片(圖片、文字是onDraw方法重繪實現(xiàn))
public class MyView extends View {
private String mtext;
private int msrc;
public MyView(Context context) {
super(context);
}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
int resourceId = 0;
int textId = attrs.getAttributeResourceValue(null, "Text",0);
int srcId = attrs.getAttributeResourceValue(null, "Src", 0);
mtext = context.getResources().getText(textId).toString();
msrc = srcId;
}
@Override
protected void onDraw(Canvas canvas) {
Paint paint = new Paint();
paint.setColor(Color.RED);
InputStream is = getResources().openRawResource(msrc);
Bitmap mBitmap = BitmapFactory.decodeStream(is);
int bh = mBitmap.getHeight();
int bw = mBitmap.getWidth();
canvas.drawBitmap(mBitmap, 0,0, paint);
//canvas.drawCircle(40, 90, 15, paint);
canvas.drawText(mtext, bw/2, 30, paint);
}
}
布局文件:
?xml version="1.0" encoding="utf-8"?
LinearLayout xmlns:android=""
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
com.example.myimageview2.MyView
android:id="@+id/myView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
Text="@string/hello_world"
Src="@drawable/xh"/
/LinearLayout
屬性Text, Src在自定義View類的構(gòu)造方法中讀取。
2)通過XML為View注冊屬性。與Android提供的標(biāo)準屬性寫法一樣。
案例: 實現(xiàn)一個帶文字說明的ImageView (ImageView+TextView組合,文字說明,可在布局文件中設(shè)置位置)
public class MyImageView extends LinearLayout {
public MyImageView(Context context) {
super(context);
}
public MyImageView(Context context, AttributeSet attrs) {
super(context, attrs);
int resourceId = -1;
TypedArray typedArray = context.obtainStyledAttributes(attrs,
R.styleable.MyImageView);
ImageView iv = new ImageView(context);
TextView tv = new TextView(context);
int N = typedArray.getIndexCount();
for (int i = 0; i N; i++) {
int attr = typedArray.getIndex(i);
switch (attr) {
case R.styleable.MyImageView_Oriental:
resourceId = typedArray.getInt(
R.styleable.MyImageView_Oriental, 0);
this.setOrientation(resourceId == 1 ? LinearLayout.HORIZONTAL
: LinearLayout.VERTICAL);
break;
case R.styleable.MyImageView_Text:
resourceId = typedArray.getResourceId(
R.styleable.MyImageView_Text, 0);
tv.setText(resourceId 0 ? typedArray.getResources().getText(
resourceId) : typedArray
.getString(R.styleable.MyImageView_Text));
break;
case R.styleable.MyImageView_Src:
resourceId = typedArray.getResourceId(
R.styleable.MyImageView_Src, 0);
iv.setImageResource(resourceId 0 ?resourceId:R.drawable.ic_launcher);
break;
}
}
addView(iv);
addView(tv);
typedArray.recycle();
}
}
attrs.xml進行屬性聲明, 文件放在values目錄下
?xml version="1.0" encoding="utf-8"?
resources
declare-styleable name="MyImageView"
attr name="Text" format="reference|string"/attr
attr name="Oriental"
enum name="Horizontal" value="1"/enum
enum name="Vertical" value="0"/enum
/attr
attr name="Src" format="reference|integer"/attr
/declare-styleable
/resources
MainActivity的布局文件:先定義命名空間 xmlns:uview="" (com.example.myimageview2為你
在manifest中定義的包名)
然后可以像使用系統(tǒng)的屬性一樣使用:uview:Oriental="Vertical"
LinearLayout xmlns:android=""
xmlns:uview=""
xmlns:tools=""
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity"
TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello_world" /
com.example.myimageview2.MyImageView
android:id="@+id/myImageView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
uview:Text="這是一個圖片說明"
uview:Src="@drawable/tw"
uview:Oriental="Vertical"
/com.example.myimageview2.MyImageView
/LinearLayout
四、控件繪制 onDraw()
五、
六:自定義View的方法
onFinishInflate() 回調(diào)方法,當(dāng)應(yīng)用從XML加載該組件并用它構(gòu)建界面之后調(diào)用的方法
onMeasure() 檢測View組件及其子組件的大小
onLayout() 當(dāng)該組件需要分配其子組件的位置、大小時
onSizeChange() 當(dāng)該組件的大小被改變時
onDraw() 當(dāng)組件將要繪制它的內(nèi)容時
onKeyDown 當(dāng)按下某個鍵盤時
onKeyUp 當(dāng)松開某個鍵盤時
onTrackballEvent 當(dāng)發(fā)生軌跡球事件時
onTouchEvent 當(dāng)發(fā)生觸屏事件時
onWindowFocusChanged(boolean) 當(dāng)該組件得到、失去焦點時
onAtrrachedToWindow() 當(dāng)把該組件放入到某個窗口時
onDetachedFromWindow() 當(dāng)把該組件從某個窗口上分離時觸發(fā)的方法
onWindowVisibilityChanged(int): 當(dāng)包含該組件的窗口的可見性發(fā)生改變時觸發(fā)的方法
不多說,先上圖:
列舉當(dāng)前目錄下的所有文件,如果是選擇目錄,則不顯示文件,如果是選擇文件,則需要顯示文件。
新建目錄,就是在當(dāng)前路徑下新建目錄,同時新建后的目錄要能夠及時顯示在文件列表中。
需要讀寫權(quán)限,添加第三方權(quán)限請求庫:
使用:
DialogFragment與Dialog有一些不同的地方,其中show方法需要傳入FragmentManager
另外需在onCreateVie方法初始化布局,以及獲取到控件
另外就是RecycleView,之所以采用RecycleView,是因為發(fā)現(xiàn)如果用ListView,內(nèi)存會不斷增加,很難降下來。
其中CommonAdapter繼承自BaseAdapter,是通用的Adapter,兼容ListView:
這一部分邏輯有FileProvider類完成; 這里需要注意的是,有些手機不支持讀取根目錄,所以改為讀取"/mnt/"作為根目錄就行讀取。
另外跳轉(zhuǎn)目錄都是改變當(dāng)前路徑,然后再刷新數(shù)據(jù)。
同時在其內(nèi)部定義了FileData類:
文件選擇,可以通過當(dāng)前路徑路徑以及列表索引來唯一確定路徑;都是,當(dāng)跳轉(zhuǎn)目錄后,索引應(yīng)該重置。
這里采用WeakReference記錄選擇的控件,但選擇其他目錄或者文件時,之前的控件需要重置一下狀態(tài)。
該源碼主要用于圖片合成gif或者視頻,其中文件選擇彈窗是自己寫的。感覺這個彈出應(yīng)該有許多地方可以用到,所以寫下這篇文章,方便以后參考查看。
效果圖:
說明:重寫LinearLayout實現(xiàn)的ViewPager指示器,可設(shè)置顯示數(shù)目,實際數(shù)目大于顯示數(shù)目時可以拖動和Fling。course的顏色,高度都寫成了自定義屬性,使用起來非常方便。
屬性:Indicator
tab_color_normal:tab文字不選中顏色
tab_color_light:tab文字選中顏色
cursor_color:course游標(biāo)顏色
cursor_height:course游標(biāo)高度
cursor_offset:course的左右縮進(大于0)
IndicatorLayout.java
使用xml
使用java
關(guān)于我:
每個view的坐標(biāo)系原點為左上角那個點,水平方向為x軸,右正左負,豎直方向為y軸,下正上負。
canvas.drawColor //繪制區(qū)域涂上顏色(設(shè)置底色/蒙層)
canvas.drawCircle(float centerX(圓心X坐標(biāo)),float centerY(圓心Y坐標(biāo)),float radius(圓的半徑,單位像素),Paint paint)
canvas.drawBitmap
canvas.drawRect(float left,float top,float right,float bottom,Paint paint) //畫矩形
canvas.drawRect(RecF rect,Paint paint)
canvas.drawRect(Rect rect,Paint paint)
canvas.drawPoint(float x(點X軸坐標(biāo)),float y(點Y軸坐標(biāo)),Paint paint)//畫點
點的大小 -paint.setStrokeWidth(width)
點的形狀 -paint.setStrokeCap(cap)
ROUND(圓形),BUTT(平頭),SQUARE(方頭)
canvas.drawPoints()//批量畫點
canvas.drawOval(float left(左邊界點),float top(上邊界點),float right(右邊界點),float bottom(下邊界點),Paint paint) //畫橢圓
canvas.drawLine(float startX(起點X軸坐標(biāo)),float startY(起點Y軸坐標(biāo)),float stopX(終點X軸坐標(biāo)),float stopY(終點X軸坐標(biāo)),Paint paint) (setStyle對直線沒有影響)
canvas.drawLines(批量畫線)
canvas.drawRoundRect(float left,float top,float right,float bottom,float rx(圓角的橫向半徑),float ry(圓角的縱向坐標(biāo)),Paint paint)//畫圓角矩形
canvas.drawRoundRect(RectF rect,float rx, float ry,Paint paint)
canvas.drawArc(float left, float top, float right, float bottom, float startAngle(起始角度,順時針為正,逆時針為負), float sweepAngle(弧形劃過角度), boolean useCenter(是否連接到圓心), Paint paint) //繪制弧形或扇形 根據(jù)弧形所在橢圓進行繪制
canvas.drawPath() //通過描述路徑的方式來繪制圖形
path.addXxx() —添加子圖形
path.addCircle(x,y,radius,dir(路徑方向:順時針/逆時針))
path.xxxTo —畫線
path.lineTo()
path.rLineTo()
path.close() —封閉當(dāng)前圖形
path.setFillType(Path.FillType ft) //設(shè)置填充模式
canvas.drawBitmap(Bitmap bitmap,float left,float top,Paint paint);//畫bitmap
canvas.drawBitmap(Bitmap bitmap,Rect src,RectF dst,Paint paint)
canvas.drawBitmap(Bitmap bitmap,Rect src,Rect dst,Paint paint)
canvas.drawBitmap(Bitmap bitmap,Matrix matrix,Paint paint)
canvas.drawText(String text,float x(起點x坐標(biāo)),float y(起點y坐標(biāo)),Paint paint) //繪制文字
Paint.setStyle //設(shè)置繪制模式
FILL 填充模式(默認)
STROKE 畫線模式
FILL_AND_STROKE 既畫線又填充
Paint.setStrokeWidth //設(shè)置線條寬度 (僅在style:Stroke、FILL_AND_STROLE下有效)
Paint.setTextSize //設(shè)置文字大小
Paint.setAntiAlias //設(shè)置抗鋸齒開關(guān)
Paint.setTextSize(float textSize)//設(shè)置文字大小
Paint.setStrokeJoin(Paint.Join join) //設(shè)置拐角的形狀
MITER//尖角(默認)
BEVEL//平角
ROUND//圓角
Paint.setStokeMiter(float miter)//設(shè)置MITER型拐角的延長線的最大值
設(shè)置顏色
直接設(shè)置顏色
Paint.setColor(int color)
Paint.setARGB(int a,int r,int g,int b)
Paint.setShader(Shader shader) //設(shè)置shader
LinearGradient 線性漸變
RadialGradient 輻射漸變
SweepGradient 掃描漸變
BitmapShader 用bitmap的像素來作為圖形或文字的填充
ComposeShader 混合著色器,多個shader混合使用
Paint.setColorFilter(ColorFilter colorFilter) //設(shè)置顏色過濾
Paint.setXfermode(Xfermode xfermode) //以要繪制的內(nèi)容為源圖像,以View中已有內(nèi)容作為目標(biāo)圖像,選取一個PorterDuff.Mode作為繪制內(nèi)容的顏色處理方案。
色彩優(yōu)化
Paint.setDither(boolean dither) //設(shè)置抖動來優(yōu)化色彩深度降低時的繪制效果
Paint.setFilterBitmap(boolean filter) //設(shè)置雙線性過濾優(yōu)化Bitmap放大繪制的效果
可以理解為 由馬賽克變成模糊狀態(tài)
Paint.setPathEffect(PathEffect effect)//使用PathEffect設(shè)置形狀的輪廓效果
CornerPathEffect//把所有的拐角變成圓角
DiscretePathEffect//把線條進行隨機的偏離
DashPathEffect//使用虛線
PathDashPathEffect//使用一個Path來繪制虛線
SumPathEffect//組合效果
ComposePathEffect//組合效果,組合有先后順序
Paint.setShadowLayer(float radius,float dx,float dy,int shadowColor)//添加陰影
Paint.setMaskFilter(MaskFilter maskfilter)//在繪制層上方的附加效果
BlurMaskFilter //模糊效果
new BlurMaskFilter(float radius(模糊范圍),BlurMaskFilter.Blur style(模糊類型))
EmbossMaskFilter//浮雕效果
new EmbossMaskFilter(float[] direction(光源的方向),float ambient(環(huán)境光強度),float specular(炫光系數(shù)),float blurRadius(光線范圍))
獲取繪制的Path
getFillPath(Path src,Path dst)//實際path
getTextPath(Stirng text,int start,int end,float x,float y,Path)/getTextPath(char[] text,int index,int count,float x,float y,Path path)//文字的path
drawTextOnPath()//沿一條Path來繪制文字
StaticLayout //繪制文字,支持換行
paint.setFakeBoldText(booleab fakeBoldText)//是否使用偽粗體
paint.setStrikeThruText()//是否加刪除線
paint.setUnderLineText(boolean underlineText)//是否加下劃線
paint.setTextSkewX(float skewX)//設(shè)置文字橫向錯切角度
paint.setTextScaleX(float scaleX)//設(shè)置文字橫向放縮
paint.setLetterSpacing(float letterSpacing)//設(shè)置字符間距,默認為0
paint.setTextAlign(Paint.Align align)//LEFT、CENTER、RIGHT默認為LEFT
paint.setTextLocale(Locale locale)/paint.setTextLocales(LocaleList locales) //設(shè)置繪制所用的地域
paint.setHinting(int mode)//是否啟用字體微調(diào)
測量文字尺寸類:
paint.getFontSpacing();//獲取推薦的行距
paint.getFontMetrics();//獲取point的FontMetrics
baseline:基準線
ascent/descent:普通字符的頂部和底部范圍
top/bottom:限制字型的頂部和底部
leading:行的額外間距,即上一行字的bottm與下一行字的top距離
paint.getTextBounds(String text(測量的文字),int start(文字的起始位置),int end(文字的結(jié)束位置),Rect bounds(文字顯示范圍的對象))//獲取文字的顯示范圍
paint.measureText(String text)//測量文字占用的寬度
measureText()getTextBounds()
paint.getTextWidths(String text,float[] widths)//獲取字符串中每個字符的寬度,并把結(jié)果填入?yún)?shù)widths
paint.breakText(String text((要測量的文字),boolean measureForwards(測量的方向),float maxWidth(寬度上限(超出上限會截斷文字)),float[] measuredWidth(用于接受數(shù)據(jù)))//測量完成后會把文字寬度賦給measureWidth[0]
paint.getRunAdvance(CharSequence text,int start(文字的起始坐標(biāo)),int end(文字的結(jié)束坐標(biāo)),int contextStart(上下文的起始坐標(biāo)),int ContextEnd(上下文的結(jié)束坐標(biāo)),boolean isRtl(文字的方向),int offset(字數(shù)的偏移))//計算某個字符處光標(biāo)的x坐標(biāo)
paint.getOffsetForAdvance(CharSequence text, int start, int end, int contextStart, int contextEnd, boolean isRtl, float advance)//計算出文字中最接近這個位置的字符偏移量
paint.hasGlyph(String s)//檢查指定的字符串是否是一個單獨的字型
canvas.clipRect()//范圍裁剪
canvas.clipPath()//根據(jù)范圍裁剪
canvas.translate(float dx,float dy)//位移
canvas.rotate(float degrees,float px,float py)//旋轉(zhuǎn)
canvas.scale(float sx(橫向縮放倍數(shù)),float sy(縱向縮放倍數(shù)),float px,float py)//縮放
canvas.skew(float sx(x軸的錯切系數(shù)),float sy(y軸的錯切系數(shù)))//錯切
canvas.setMatrix(matrix)//用Matrix直接替換Canvas當(dāng)前的變換矩陣
canvas.concat(matrix)//用Canvas當(dāng)前的變換矩陣和Matrix相乘
Camera.rotate*()//三維旋轉(zhuǎn)
1、super.draw()//總調(diào)度方法
2、super.onDraw()
3、dispatchDraw()//繪制子View的方法
繪制順序:
draw()總調(diào)度方法,view的繪制過程都發(fā)生在draw()方法里
1、背景(drawBackground()不能重寫)-------android:background:/View.setBackgroundXxx()
2、主體(onDraw())
3、子View(dispatchDraw())
4、滑動邊緣漸變和滑動條(onDrawForeground())-------android:scrollbarXxx/View.setXXXScrollBarXXX()
5、前景(onDrawForeground())-------android:foreground/View.setForeground()
view.animate().translationX()//x軸偏移
1、如果是自定義控件,需要添加setter、getter方法
2、ObjectAnimator.ofXXX()創(chuàng)建ObjectAnimator對象
3、用start()方法執(zhí)行動畫
setDuration(int duration)//設(shè)置動畫時長
setInterpolator(Interpolator interpolator)//設(shè)置插值器
ViewPropertyAnimator.setListener()/ObjectAnimator.addListener()
ViewPropertyAnimator.setUpdateListener()/ObjectAnimator.addUpdateListener()
ObjectAnimator.addPauseListener()
ViewPropertyAnimator.withStartAction/EndAction()
ArgbEvaluator//顏色漸變動畫
PropertyValuesHolder//同一個動畫中改變多個屬性
PropertyValuesHolders.ofKeyframe()//把同一個屬性拆分
AnimatorSet//多個動畫配合執(zhí)行
targetSdkVersion=14,硬件加速默認開啟
view.setLayerType()
LAYER_TYPE_SOFTWARE:使用軟件來繪制View Layer,繪制到Bitmap,并順便關(guān)閉硬件加速
LAYER_TYPE_HARDWARE:使用GPU來繪制View Layer,繪制到OpenGL texture(如果硬件加速關(guān)閉,那么行為和LAYER_TYPE_SOFTWARE一致)
LAYER_TYPE_NONE:關(guān)閉View Layer
View Layer可以加速無invalidate()(例如動畫)時的刷新效率,但對于需要調(diào)用invalidate()的刷新無法加速
硬件加速并不支持所有的繪制操作
1、測量(measure)
View:View在onMeasuer中會計算自己的尺寸然后保存
ViewGroup:ViewGroup在onMeasure中會調(diào)用所有子View的measure讓它們進行自我測量,并根據(jù)子View
計算出的期望尺寸來計算他們的事跡尺寸和位置然后保存。
2、布局(layout)
View:無子View所以onLayout不做任何處理
ViewGroup:ViewGroup在onLayout中會調(diào)用自己所有子View的layout方法,把他們的尺寸、位置傳給他們, 讓他們完成自我布局。
MeasureSpec = mode + size :父類傳遞過來給當(dāng)前View的一個建議值
MeasureSpec.getMode(int spec)//獲取模式
MeasureSpec.getSize(int spec)//獲取數(shù)值
限制分類:
UNSPECIFIED(不限制)
AT_MOST(限制上限)-wrap_content
EXACTLY(限制固定值)-match_parent/具體值
1、重寫onMeasure來修改已有的View尺寸
(1)、重寫onMeasure方法,調(diào)用super.onMeasure觸發(fā)原有的自我測量。
(2)、在super.onMeasure下用getMeasureWidth與getMeasureHeigh獲取之前測量的結(jié)果,使用自己的算法計算新結(jié)果。
(3)、調(diào)用setMeasureDimension保存新結(jié)果。
2、重寫onMeasure來全新定制自定義View的尺寸
與1區(qū)別,保證計算的同時,保證結(jié)果滿足父View給出的尺寸限制
(1)重寫onMeasure,計算出View的尺寸
(2)使用resolve讓子View的計算結(jié)果符合父View的限制,也可不使用該方法自己定義
3、重寫onMeasure和onLayout來全新定制自定義ViewGroup的內(nèi)部布局
兩個注意點:
子控件間的margin值
1、重寫generateLayoutParams()和generateDefaultLayoutParams()
2、獲取margin值 MarginLayoutParams lp = (MarginLayoutParams )child.getLayoutParams()
子控件間的padding值
1、測量后直接getPaddingLeft、getPaddingTop、getPaddingRight、getPaddingBottom
重寫onMeasure來計算內(nèi)部布局
(1)調(diào)用每個子View的measure來計算子View的尺寸
結(jié)合layout_xxx和自己可用空間
(2)計算子View的位置并保存子View的尺寸和位置
(3)計算自己的尺寸并用setMeasureDimension保存
重寫onLayout來擺放子View
(1)調(diào)用每個子View的layout,讓他們保存自己的位置和尺寸
view工作原理
觸摸事件
1、ACTION_DOWN:手指剛接觸屏幕,按下去的那一瞬間
2、ACTION_MOVE:手指在屏幕上移動
3、ACTION_UP:手指從屏幕上松開的瞬間
事件序列:從ACTION_DOWN - ACTION_UP
ViewGroup:
DispatchTouchEvent
? return true:表示該View內(nèi)部消化掉了所有事件
? return false:表示事件在本層不再繼續(xù)進行分發(fā),并交由上層控件的onTouchEvent方法進行消費
? return super.dispatchTouchEvent(ev):默認事件將分發(fā)給本層的事件攔截onInterceptTouchEvent方法 進行處理
OnInterceptTouchEvent
? return true:表示將事件進行攔截,并將攔截到的事件交由本層控件的onTouchEvent進行處理
? return false:表示不對事件進行攔截,事件得以成功分發(fā)到子View
? return super.onInterceptTouchEvent(ev):默認表示不攔截該事件,并將事件傳遞給下一層View的 dispatchTouchEvent
OnTouchEvent 默認false
? return true:表示onTouchEvent處理完事件后消費了此次事件
? return fasle:表示不響應(yīng)事件,那么該事件將會不斷向上層View的onTouchEvent方法傳遞,直到某個View的 onTouchEvent方法返回true
? return super.dispatchTouchEvent(ev):表示不響應(yīng)事件,結(jié)果與return false一樣
子View不存在分發(fā):
? DispatchTouchEvent 事件分發(fā)
? OnTouchEvent 默認true
如下圖為事件分發(fā)流程圖:
---------------------- 以上總結(jié)部分源自Hencoder教程 ------------------------------
? 組合控件:即由原生控件拼裝而成,不需要自己實現(xiàn)或者繪制具體的頁面內(nèi)容和效果,常用于標(biāo)題欄TitlleView
? ? eg:
???繼承控件的意思就是,我們并不需要自己重頭去實現(xiàn)一個控件,只需要去繼承一個現(xiàn)有的控件,然后在這個控件上增加一些新的功能,就可以形成一個自定義的控件了。這種自定義控件的特點就是不僅能夠按照我們的需求加入相應(yīng)的功能,還可以保留原生控件的所有功能。
熟悉view的繪制原理
1.measure用來測量View的寬和高。?
2.layout用來確定View在父容器中放置的位置。?
3.draw用來將view繪制在屏幕上
標(biāo)題名稱:android自定控件,Android自定義控件高級進階與精彩實例
當(dāng)前地址:http://vcdvsql.cn/article22/dsiiejc.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)頁設(shè)計公司、外貿(mào)建站、品牌網(wǎng)站建設(shè)、網(wǎng)站收錄、Google、微信小程序
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)