編輯:關於Android編程
首先,自定義控件分為三類:
自定義的組合控件
繼承View的自定義控件
繼承ViewGroup的自定義控件
在這裡,我要寫的是第二種,也就是繼承自View的自定義控件,第一種自定義的組合控件,我已經寫過了,可以在我的博客中可以找到
現在來看一下繼承View的自定義控件
首先,需要寫一個類繼承自View,那麼,它也有三個構造方法,有一個參數的構造方法實在代碼中new這個自定義控件時被調用;有兩個參數的構造方法是在布局中使用這個自定義控件的時候調用,有三個參數的構造方法,實在使用到這個自定義控件的樣式時被調用;同樣,用到那個就重寫那個
其次,需要重寫onMeasure()方法和onDraw()方法
onMeasure()方法是為了測量控件自己的寬高,onDraw()方法是為了繪制的內容,如果你繼承的是ViewGroup,那麼你還需要重寫onLayout()方法
最後,實現業務邏輯
在這裡,我實現的是一個開關的效果
如下圖:
這是可以滑動和點擊的
自定義屬性的步驟,具體請參考我的自定義的組合控件,哪裡已經做了詳細說明
1、先自定義一個類繼承View
// 在代碼中創建控件
public MyButton(Context context) {
super(context);
}
// 控件使用在xml布局文件中
public MyButton(Context context, AttributeSet attrs) {
super(context, attrs);
}
// 使用樣式時
public MyButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
接下來,你需要在布局中使用這個控件,用全類名
2、重寫onMeasure()方法
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//把背景圖片的寬高作為控件的寬高
setMeasuredDimension(mSwitchBackground.getWidth(), mSwitchBackground.getHeight());
}
3、重寫onDraw()方法
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(mSwitchBackground, 0, 0, null);
if(!isTouching){
//根據當前狀態滑動圖片
int left = 0;
if(currentToggleState){ //如果是打開狀態,左邊距等於背景的寬度-滑塊的寬度
left = mSwitchBackground.getWidth() - mSlideButton.getWidth();
}else {
//關閉狀態
left = 0;
}
canvas.drawBitmap(mSlideButton, left, 0, null);
}else{
//根據手指觸摸的位置,繪制滑動的圖片
int left = currentX - mSlideButton.getWidth() / 2; //為了讓用戶感覺手在圖片中間滑動
if(left < 0){ //圖片超出左邊界,直接繪制到0位置
left = 0;
}else if(left >= mSwitchBackground.getWidth() - mSlideButton.getWidth()){ //圖片超出右邊界,直接繪制到右邊
left = mSwitchBackground.getWidth() - mSlideButton.getWidth();
}
canvas.drawBitmap(mSlideButton, left, 0, null);
}
}
接下來就是處理自己的業務邏輯
在這裡,我把代碼全部放在這裡了,這是MyButton .java
public class MyButton extends View {
private Bitmap mSwitchBackground;
private Bitmap mSlideButton;
private boolean currentToggleState; //記錄當前開關的狀態
private int currentX;
private boolean isTouching = false; //記錄當前控件是否處於觸摸中
private MyButtonOnStateChangedListener listener;
private String namespace = "http://schemas.android.com/apk/res/com.abc.togglestate";
/**
* 在代碼中創建控件調用
* @param context,
*/
public MyButton(Context context) {
super(context);
}
/**
* 控件使用在xml布局中使用
* @param context
* @param attrs
*/
public MyButton(Context context, AttributeSet attrs) {
super(context, attrs);
//獲取布局文件中的屬性
int backgroundRes = attrs.getAttributeResourceValue(namespace, "backgroundRes",0);
setBackgroundRes(backgroundRes);
int slideButtonRes = attrs.getAttributeResourceValue(namespace, "slideButtonRes", 0);
setSlidButtonBackgroundRes(slideButtonRes);
currentToggleState = attrs.getAttributeBooleanValue(namespace, "state", false);
}
/**
* 使用樣式時調用
* @param context
* @param attrs
* @param defStyle
*/
public MyButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
/**
* 測量自己的寬高
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//把背景圖片的寬高作為控件的寬高
setMeasuredDimension(mSwitchBackground.getWidth(), mSwitchBackground.getHeight());
}
/**
* 繪制內容
*/
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(mSwitchBackground, 0, 0, null);
if(!isTouching){
//根據當前狀態滑動圖片
int left = 0;
if(currentToggleState){ //如果是打開狀態,左邊距等於背景的寬度-滑塊的寬度
left = mSwitchBackground.getWidth() - mSlideButton.getWidth();
}else {
//關閉狀態
left = 0;
}
canvas.drawBitmap(mSlideButton, left, 0, null);
}else{
//根據手指觸摸的位置,繪制滑動的圖片
int left = currentX - mSlideButton.getWidth() / 2; //為了讓用戶感覺手在圖片中間滑動
if(left < 0){ //圖片超出左邊界,直接繪制到0位置
left = 0;
}else if(left >= mSwitchBackground.getWidth() - mSlideButton.getWidth()){ //圖片超出右邊界,直接繪制到右邊
left = mSwitchBackground.getWidth() - mSlideButton.getWidth();
}
canvas.drawBitmap(mSlideButton, left, 0, null);
}
}
/**
* 給控件設置背景圖片
* @param switchBackground
*/
public void setBackgroundRes(int switchBackground) {
mSwitchBackground = BitmapFactory.decodeResource(getResources(),switchBackground);
}
/**
* 給控件設置滑塊
* @param slideButtonBackground
*/
public void setSlidButtonBackgroundRes(int slideButtonBackground) {
mSlideButton = BitmapFactory.decodeResource(getResources(), slideButtonBackground);
}
/**
* 開關的狀態(這裡沒有用到)
* 用於外部調用
* @param toggleState
*/
public void isState(boolean toggleState) {
currentToggleState = toggleState;
}
/**
* 處理觸摸事件
* 觸摸後,獲取當前的觸摸位置,根據位置,更新控件
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
isTouching = true;
currentX = (int) event.getX();
break;
case MotionEvent.ACTION_MOVE:
currentX = (int) event.getX();
break;
case MotionEvent.ACTION_UP:
isTouching = false;
currentX = (int) event.getX();
//手抬起後,更改當前控件的狀態,根據當前手觸摸的 位置和背景圖片的中間值進行比較
boolean tempState = currentX >= mSwitchBackground.getWidth() / 2;
//6.3、判斷當前的狀態是否發生變化
if(tempState != currentToggleState){
currentToggleState = tempState;
if(listener != null){
listener.OnStateChanged(currentToggleState);
}
}
break;
}
invalidate(); //重新繪制控件,自動觸發onDraw(在主線程中繪制控件)
//postInvalidate(); //重新繪制控件,自動觸發onDraw(在子線程中繪制控件)
return true; //自己消費事件
}
//6.1、對外提供開關監聽
public interface MyButtonOnStateChangedListener{
public void OnStateChanged(boolean state);
}
//6.2、讓外界把監聽器傳進來
public void setMyButtonOnStateChangedListener(MyButtonOnStateChangedListener listener){
this.listener = listener;
}
}
MainActivity.java代碼如下
public class MainActivity extends Activity {
private MyButton mybutton;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mybutton = (MyButton) findViewById(R.id.mybutton);
mybutton.setMyButtonOnStateChangedListener(new MyButtonOnStateChangedListener() {
@Override
public void OnStateChanged(boolean state) {
//出來開關狀態業務發生變化
Toast.makeText(getApplicationContext(), "" + state, 0).show();
}
});
}
}
希望能對看到這篇博客的小伙伴有所幫助,僅供大家參考
在項目中,經常需要判斷是否有網絡連接。最近學習了如何判斷軟件是否聯網,如果沒有聯網,彈出提示信息,連接網絡。效果:(1)聯網情況下: (2)不聯網情況下:(3)
Android與服務器之間的通訊方式主要有兩種。一種是Http通訊 , 一種是Socket通訊。兩者最大的差異在於,Http連接使用的是“請求---響應方式&
Android有自帶的對話框標題,但是不太美觀,如果要給彈出的對話框設置一個自定義的標題,使用AlertDialog.Builder的setCustomTitle()方法
之前的10篇博文主要是記錄了Android4.2.2的SurfaceFlinger的相關內容,為何之前會投入那麼多的時間,原因就在於之前在看camera的架構時,遇到了本