當前位置:首頁 » 安卓系統 » android自定義view事件

android自定義view事件

發布時間: 2023-02-11 22:26:02

『壹』 Android 自定義View

1.直接在XML文件中定義的 ==》布局文件。
2.在XML文件中通過style這個屬性定義的 ==》在布局中使用自定義屬性樣式。
3.通過defStyleAttr定義的 ==》在View的構造方法中使用自定義屬性樣式。
4.通過defStyleRes定義的 ==》在View的構造方法中使用自定義樣式。
5.直接在當然工程的theme主題下定義的 ==》AndroidManifest.xml中設置。

1、onMeasure 測量自身,自定義View時重寫,定義控制項的寬高,常在自定義的View中使用
2、Measure 測量自身,方法不可重寫,內部調用onMeasure方法,常在自定義的ViewGroup中使用
3、measureChild 測量某個子View,內部調用Measure方法,常在自定義的ViewGroup中使用
4、measureChildren 測量所有子View,內部調用measureChild方法,常在自定義的ViewGroup中使用

在自定義View的開發中,我們重寫測量方法,方法里的傳參(widthMeasureSpec,heightMeasureSpec)都是由父類提供的,在自定義ViewGroup的開發中,我們可以根據當前布局的測量參數,為布局內的子控制項創建新的測量參數,來控制子View在布局的顯示大小

1、layout:指定View新的顯示位置,用法:view.layout(left,top,right,bottom);
2、onLayout:設置View的顯示位置,用法:重寫該方法,定義View的顯示規則
3、requestLayout:強制View重新布局,用法:view.requestLayout();

onFinishInflate -> onAttachedToWindow -> onMeasure -> onSizeChanged -> onLayout -> onDraw -> onDetachedFromWindow

Android的事件分發可以理解為向下分發,向上回傳,類似V字型,V字的左邊是事件進行向下分發,如果途中沒有進行事件的分發攔截,則事件傳遞到最底層的View,即是最接近屏幕的View。V字的右邊是事件的回傳,如果中途沒有進行事件的消費,則事件傳遞到最頂層的View,直至消失。

『貳』 Android自定義View

View的構造函數:共有4個

系統自帶的View可以在xml中配置屬性,對於寫的好的自定義View同樣可以在xml中配置屬性,為了使自定義的View的屬性可以在xml中配置,需要以下4個步驟:

一定要記住:無論是measure過程、layout過程還是draw過程,永遠都是從View樹的根節點開始測量或計算(即從樹的頂端開始),一層一層、一個分支一個分支地進行(即樹形遞歸),最終計算整個View樹中各個View,最終確定整個View樹的相關屬性。

Android的坐標系定義為:

View的位置由4個頂點決定的 4個頂點的位置描述分別由4個值決定:

View的位置是通過view.getxxx()函數進行獲取:(以Top為例)

與MotionEvent中 get()和getRaw()的區別

MarginLayoutParams是和外間距有關的。事實也確實如此,和LayoutParams相比,MarginLayoutParams只是增加了對上下左右外間距的支持。實際上大部分LayoutParams的實現類都是繼承自MarginLayoutParams,因為基本所有的父容器都是支持子View設置外間距的。

1. 創建自定義屬性

2. 繼承MarginLayout

3. 重寫ViewGroup中幾個與LayoutParams相關的方法

在為View設置LayoutParams的時候需要根據它的父容器選擇對應的LayoutParams,否則結果可能與預期不一致,這里簡單羅列一些常見的LayoutParams子類:

測量規格,封裝了父容器對 view 的布局上的限制,內部提供了寬高的信息( SpecMode 、 SpecSize ),SpecSize是指在某種SpecMode下的參考尺寸,其中SpecMode 有如下三種:

針對上表,這里再做一下具體的說明

一般getIntrinsicWidth/Height能獲得內部寬/高 圖片Drawable其內部寬高就是圖
片的寬高 顏色Drawable沒有內部寬高的概念 內部寬高不等同於它的大小,一般
Drawable沒有大小概念(作為View背景時,會被拉伸至View的大小)

『叄』 android 自定義view滑動和點擊事件沖突怎麼解決

在Android中,對一個View同時調用OnTouch事件和OnClick事件時,導致事件沖突,比如onClick事件打算執行A動作,OnTouch事件打算執行B動作,但是在實際使用時會發現,當調用OnTouch時,有可能會同時執行A,B兩個動作,這是因為OnClick事件本身就是在OnTouch事件中發生的;在onTouch事件中,如果返回true,就不會執行onClick,返回false,就同時執行onClick方法,要想把OnTouch和onClick事件完全的區分。可能過下列方法,解決該沖突問題:
就是在 OnTouch中的MotionEvent.ACTION_DOWN 時,記錄下點(X1,Y1),
在 MotionEvent.ACTION_UP 時,記錄下點(X2,Y2),然後比對 倆點之間的距離,如果小於一個較小數值(比如5),就認為是Click事件,onTouch中返回false,如果距離較大,可以當作onTouch事件去處理,返回true:
示範如下:
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
x1 = event.getX();
y1 = event.getY();
}
if (event.getAction() == MotionEvent.ACTION_UP) {
x2 = event.getX();
y2 = event.getY();
if (Math.abs(x1 - x2) < 6) {
return false;// 距離較小,當作click事件來處理
}
if(Math.abs(x1 - x2) >60){ // 真正的onTouch事件
}
}
return true;// 返回true,不執行click事件
}

『肆』 Android TextView Html超鏈接實現自定義點擊事件處理

第一步:自定義ClickableSpan

第二步:處理html

第三步:設置給textView

至此就能首先自定義點擊了。

『伍』 Android 自定義View之Draw過程(上)

Draw 過程系列文章

Android 展示之三部曲:

前邊我們已經分析了:

這倆最主要的任務是: 確定View/ViewGroup可繪制的矩形區域。
接下來將會分析,如何在這給定的區域內繪制想要的圖形。

通過本篇文章,你將了解到:

Android 提供了關於View最基礎的兩個類:

然而ViewGroup 並沒有約定其內部的子View是如何布局的,是疊加在一起呢?還是橫向擺放、縱向擺放等。同樣的View 也沒有約定其展示的內容是啥樣,是矩形、圓形、三角形、一張圖片、一段文字抑或是不規則的形狀?這些都要我們自己去實現嗎?
不盡然,值得高興的是Android已經考慮到上述需求了,為了開發方便已經預制了一些常用的ViewGroup、View。
如:
繼承自ViewGroup的子類

繼承自View的子類

雖然以上衍生的View/ViewGroup子類已經大大為我們提供了便利,但也僅僅是通用場景下的通用控制項,我們想實現一些較為復雜的效果,比如波浪形狀進度條、會發光的球體等,這些系統控制項就無能為力了,也沒必要去預制千奇百怪的控制項。想要達到此效果,我們需要自定義View/ViewGroup。
通常來說自定義View/ViewGroup有以下幾種:

3 一般不怎麼用,除非布局比較特殊。1、2、4 是我們常用的手段,對於我們常說的"自定義View" 一般指的是 4。
接下來我們來看看 4是怎麼實現的。

在xml里引用MyView

效果如下:

黑色部分為其父布局背景。
紅色矩形+黃色圓形即是MyView繪制的內容。
以上是最簡單的自定義View的實現,我們提取重點歸納如下:

由上述Demo可知,我們只需要在重寫的onDraw(xx)方法里繪制想要的圖形即可。
來看看View 默認的onDraw(xx)方法:

發現是個空實現,因此繼承自View的類必須重寫onDraw(xx)方法才能實現繪制。該方法傳入參數為:Canvas類型。
Canvas翻譯過來一般叫做畫布,在重寫的onDraw(xx)里拿到Canvas對象後,有了畫布我們還需要一支筆,這只筆即為Paint,翻譯過來一般稱作畫筆。兩者結合,就可以愉快的作畫(繪制)了。
你可能發現了,在Demo里調用

並沒有傳入Paint啊,是不是Paint不是必須的?實際上調用該方法後,底層會自動生成Paint對象。

可以看到,底層初始化了Paint,並且給其設置的顏色為在java層設置的顏色。

onDraw(xx)比較簡單,開局一個Canvas,效果全靠畫。
試想,這個Canvas怎麼來的呢,換句話說是誰調用了onDraw(xx)。發揮一下聯想功能,在Measure、Layout 過程有提到過兩者套路很像:

那麼Draw過程是否也是如此套路呢?看見了onDraw(xx),那麼draw(xx)還遠嗎?
沒錯,還真有draw(xx)方法:

可以看出,draw(xx)主要分為兩個部分:

不管是A分支還是B分支,都進行了好幾步的繪制。
通常來說,單一一個View的層次分為:

後面繪制的可能會遮擋前邊繪制的。
對於一個ViewGroup來說,層次分為:

來看看A分支標注的4個點:
(1)
onDraw(canvas)
前面分析過,對於單一的View,onDraw(xx)是空實現,需要由我們自定義繪制。
而對於ViewGroup,也並沒有具體實現,如果在自定義ViewGroup里重寫onDraw(xx),它會執行嗎?默認是不會執行的,相關分析請移步:
Android ViewGroup onDraw為什麼沒調用

(2)
dispatchDraw(canvas),來看看在View.java里的實現:

發現是個空實現,再看看ViewGroup.java里的實現:

也即是說,對於單一View,因為沒有子布局,因此沒必要再分發Draw,而對於ViewGroup來說,需要觸發其子布局發起Draw過程(此過程後續分析),可以類比事件分發過程View、ViewGroup的處理。感興趣的請移步:
Android 輸入事件一擼到底之View接盤俠(3)

(3)
OverLay,顧名思義就是"蓋在某個東西上面",此處是在繪制內容之後,繪制前景之前。怎麼用呢?

以上是給一個ViewGroup設置overLay,效果如下:

你可能發現了,這和設置overLay差不多的嘛,實際還是有差別的。在onDrawForeground(xx)里會重新調整Drawable的尺寸,該尺寸與View大小一致,之前給Drawable設置的尺寸會失效。運行效果如下:

可以看出,ViewGroup都被前景蓋住了。
再來看看B分支的重點:邊緣漸變效果
先來看看TextView 邊緣漸變效果:

加上這倆參數。
實際上系統自帶的一些控制項也使用了該效果,如NumberPicker、YearPickerView

以上是NumberPicker 的效果,可以看出是垂直方向漸變的。

對於View.java 里的onDraw(xx)、draw(xx),ViewGroup.java里並沒有重寫。
而對於dispatchDraw(xx),在View.java里是空實現。在ViewGroup.java里發起對子布局的繪制。

來看看標記的2點:
(1)
設置padding的目的是為了讓子布局留出一定的空隙出來,因此當設置了padding後,子布局的canvas需要根據padding進行裁減。判斷標記為:

FLAG_CLIP_TO_PADDING 默認設置為true
FLAG_PADDING_NOT_NULL 只要有padding不為0,該標記就會打上。
也就是說:只要設置了padding 不為0,子布局顯示區域需要裁減。
能不能不讓子布局裁減顯示區域呢?
答案是可以的。
考慮到一種場景:使用RecyclerView的時候,我們需要設置paddingTop = 20px,效果是:RecyclerView Item展示時離頂部有20px,但是滾動的時候永遠滾不到頂部,看起來不是那麼友好。這就是上述的裁減起作用了,需要將此動作禁止。通過設置:

當然也可以在xml里設置:

(2)
drawChild(xx)

從方法名上看是調用子布局進行繪制。
child.draw(x1,x2,x3)里分兩種情況:

這兩者具體作用與區別會在下篇文章分析,不管是硬體加速繪制還是軟體加速繪制,最終都會調用View.draw(xx)方法,該方法上面已經分析過。
注意,draw(x1,x2,x3)與draw(xx)並不一樣,不要搞混了。

用圖表示:

View/ViewGroup Draw過程的聯系:

一般來說,我們通常會自定義View,並且重寫其onDraw(xx)方法,有沒有繪制內容的ViewGroup需求呢?
是有的,舉個例子,大家可以去看看RecyclerView ItemDecoration 的繪制,其中運用到了ViewGroup draw(xx)、ViewGroup onDraw(xx) 、View onDraw(xx)繪制的先後順序來實現分割線,分組頭部懸停等功能的。

本篇文章基於 Android 10.0

『陸』 Android開發 自定義View

Android自定義View實現很簡單:
1、繼承View,重寫構造函數、onDraw,(onMeasure)等函數。
2、如果自定義的View需要有自定義的屬性,需要在values下建立attrs.xml。在其中定義你的屬性。
3、在使用到自定義View的xml布局文件中需要加入xmlns:前綴="http://schemas.android.com/apk/res/你的自定義View所在的包路徑".
4、在使用自定義屬性的時候,使用前綴:屬性名,如my:textColor="#FFFFFFF"。
實例:
自定義TextView類:
復制代碼
package com.zst.service.component;
import com.example.hello_wangle.R;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
public class MyTextView extends TextView {
//不能在布局文件中使用
public MyTextView(Context context) {
super(context);
}

//布局文件中用到此構造函數

『柒』 Carson帶你學Android:手把手教你寫一個完整的自定義View

自定義View一共分為兩大類,具體如下圖:

對於自定義View的類型介紹及使用場景如下圖:

在使用自定義View時有很多注意點(坑),希望大家要非常留意:

View的內部本身提供了post系列的方法,完全可以替代Handler的作用,使用起來更加方便、直接。

主要針對View中含有線程或動畫的情況: 當View退出或不可見時,記得及時停止該View包含的線程和動畫,否則會造成內存泄露問題

當View帶有滑動嵌套情況時,必須要處理好滑動沖突,否則會嚴重影響View的顯示效果。

接下來,我將用自定義View中最常用的 繼承View 來說明自定義View的具體應用和需要注意的點

在下面的例子中,我將講解:

下面我將逐個步驟進行說明:
步驟1:創建自定義View類(繼承View類)

特別注意:

步驟2:在布局文件中添加自定義View類的組件及顯示

至此,一個基本的自定義View已經實現了,運行效果如下圖。

接下來繼續看自定義View關於屬性自定義的問題:

先來看wrap_content & match_parent屬性的區別

如果不手動設置支持 wrap_content 屬性,那麼 wrap_content 屬性是不會生效(顯示效果同 match_parent )

padding 屬性:用於設置控制項內容相對控制項邊緣的邊距;

如果不手動設置支持padding屬性,那麼padding屬性在自定義View中是不會生效的。

繪制時考慮傳入的padding屬性值(四個方向)。

除了常見的以android:開頭的系統屬性(如下所示),很多場景下自定義View還需要系統所沒有的屬性,即自定義屬性。

實現自定義屬性的步驟如下:

下面我將對每個步驟進行具體介紹

對於自定義屬性類型 & 格式如下:

至此,一個較為規范的自定義View已經完成了。

Carson_Ho的github: 自定義View的具體應用

不定期分享關於 安卓開發 的干貨,追求 短、平、快 ,但 卻不缺深度

『捌』 Android:一篇文章帶你完全梳理自定義View工作流程!

了解自定義View流程前,需了解一定的自定義View基礎,具體請看文章: (1)自定義View基礎 - 最易懂的自定義View原理系列

下面,我將詳細講解 View 繪制的三大流程: measure 過程、 layout 過程、 draw 過程

請看文章: 自定義View Layout過程 - 最易懂的自定義View原理系列(3)

至此,關於自定義 View 的工作流程講解完畢。

結合原理 & 實現步驟,若需實現1個自定義View,請看文章: 手把手教你寫一個完整的自定義View

『玖』 Android自定義View之區塊選擇器

先來看下效果吧:

我們來分析這個view需要實現哪些效果。

別害怕有這么多的功能,我們一個一個來實現。首先是刻度尺,這個簡單。由於完整的刻度尺是比屏幕寬度大的,因此我們先來了解幾個概念:

這裏手機屏幕的寬度是width,刻度尺的寬度的時maxWidth,我們其實只需要繪制手機屏幕可見的部分就可以了,這里的offset表示手機屏幕的左邊與刻度尺左邊的偏移量。

了解了這個概念,我們就來開始寫吧,定義一個View,處理下構造都指向3個參數的那個,然後統一做初始化:

我們在onMeasure中處理了wrap_content的高度。然後在onSizeChanged中獲取尺寸參數:

接著就開始繪制吧:

這里的titles代表了刻度的標識,每一個元素代表一個刻度(這里我位元組寫死了,實際上可以通過方法set,也不一定是時間,能代表刻度的都可以)。通過rate設置長短刻度的比例,這里我設置了1:1。運行一下看看,目前僅僅能看到從0開始,看不到完整的刻度尺,我們需要實現touch事件產生移動才有效果。

我們重寫onTouchEvent來實現滑動效果:

我們計算出每次move事件的X方向的變化量dx,然後通過這個dx改變offset,並且處理一下邊界的情況。然後調用postInvalidate刷新界面。
運行一下看看!現在我們可以滑動刻度尺了。但是好像還有點問題,平時我們使用ScrollView的時候用力劃一下,可以看到手指離開了屏幕,但是內容還可以繼續滾動。而目前我們自定義的這個view只能通過手指滑動,如果手指離開屏幕就不能滑動了。這樣的體驗顯然不夠好,我們來實現這個慣性滑動的效果吧!

要實現慣性滑動,我們需要用到兩個類:VelocityTracker,OverScroller。
VelocityTracker簡介
view滑動助手類OverScroller

velocityTracker.computeCurrentVelocity方法的第二個參數表示最大慣性速度,這里我設置8000,避免刻度尺過快的滑動。通過調用scroller.fling方法將計算出的速度交給scroller,然後在computeScroll方法中獲取當前值,並與上一次的值做差算出變化量dx,同樣用這個dx變化offset刷新界面實現滑動效果。

刻度尺完成了,接下來是不可選的灰色區域。我採用兩個int值表示在刻度尺的區域,刻度尺的每個刻度表示一個最小單位,前一個int表示在刻度尺的起始位置,後一個int表示占據的刻度數量。

我用一個list存放設置的不可選區域,然後在另一個list中存放轉換成RectF的位置信息。這里的RectF是在相對於整體刻度尺而言的,因此繪制到屏幕的時候需要減去offset,並且需要考慮只有部分在屏幕可見的情況。避免在onDraw方法中創建過多臨時變數,我聲明一個成員變數tempRect,用來保存繪制時的臨時參數。

完成了不可選區域,可選區域也是同樣的。由於只能有一個可選區域,我們只需要定義一個RectF。額外需要考慮與不可選區域相交時會變色,我定了一個overlapping表示是否相交,通過RectF的intersects方法判斷。

通過前面的分析,我們知道這個view中的事件有很多種:點擊,移動刻度尺,移動選中區域,擴展選中區域。我們定義這四種類型便於後續的事件處理:

然後改造一下onTouchEvent:

performClick會在你重寫onTouchEvent時as提示你需要重寫的方法,因為你可能沒有考慮到如果給這個view設置OnClickListener的情況。如果你沒有在onTouchEvent中調用performClick,那麼setOnClickListener方法就失效了。

你可能注意到這一次比較復雜,並且還有一個linking欄位,表示是否正在聯動,我解釋一下這個聯動的概念:通過gif其實你可能注意到,當我移動或者擴展選中區域的時候,如果移動到了屏幕的邊界,後面的刻度尺就會跟著移動,實際上這個時候選中區域在屏幕中的位置沒有改變,只是刻度尺移動了。一開始我也是通過dx來改變offset,但是存在一個問題,移動到屏幕邊緣之後,手指可以移動的區域已經很小了,不會產生足夠的dx(手指不移動的話,不會有新的touch事件產生)。最好的體驗是我把手機移動到屏幕邊緣,刻度尺就會自己按照一定的速率移動直到最大offset或者最小offset。於是我使用了Handler,當滿足條件後發送消息,表示開始進行聯動,會按照固定速度產生一個dx改變offset。當然,在離開屏幕邊緣的時候還需要及時取消handler的任務。

至此,功能基本已經實現了,運行一下看看效果吧~

後面需要做什麼那?現在這個view只能自己玩,我需要它與其他view有交互,比如選中什麼區域,狀態的改變生么的。

聲明兩個介面,並在適當時候回調它們的方法,這樣外部就能感知view的狀態變化。

後面的話就是根據業務添加一些api了,例如添加不可選區域,改變刻度范圍什麼,一切都看需求了。

想學習更多Android知識,或者獲取相關資料請加入Android開發交流群:1018342383。 有面試資源系統整理分享,Java語言進階和Kotlin語言與Android相關技術內核,APP開發框架知識, 360°Android App全方位性能優化。Android前沿技術,高級UI、Gradle、RxJava、小程序、Hybrid、 移動架構師專題項目實戰環節、React Native、等技術教程!架構師課程、NDK模塊開發、 Flutter等全方面的 Android高級實踐技術講解。還有在線答疑

『拾』 android中,我自定義一個View,然後在XMl中載入它,且我在XML中添加了Button按鈕,在哪裡添加事件。

事件是自己重寫的 事例如下:

Button b = (Button)findViewById(R.id.button1);
b.setOnClickListener(new View.OnClickListener() {

@Override
public void onClick(View v) {

//按下後干什麼,代碼就寫在這里

}
});

若有疑問請繼續提出,若幫到你,望採納!

熱點內容
我配置很高了ae為什麼卡 發布:2025-05-17 14:54:50 瀏覽:167
python數據分析實戰pdf 發布:2025-05-17 14:49:42 瀏覽:950
海瀾之家廣告腳本 發布:2025-05-17 13:56:06 瀏覽:32
手文件夾恢復 發布:2025-05-17 13:53:32 瀏覽:995
linux怎麼看進程 發布:2025-05-17 13:53:30 瀏覽:305
thinkphp欄位緩存 發布:2025-05-17 13:52:01 瀏覽:577
山靈app安卓版如何設置 發布:2025-05-17 13:51:49 瀏覽:390
帆布壓縮袋 發布:2025-05-17 13:26:27 瀏覽:462
c語言16進製表示方法 發布:2025-05-17 13:11:25 瀏覽:484
ftp單位 發布:2025-05-17 13:10:03 瀏覽:146