Android筆記——Android自定義控件

目錄:

 

1.自定義控件概述

01_什麼是自定義控件

  Android系統中,繼承Android系統自帶的View或者ViewGroup控件或者系統自帶的控件,並在這基礎上增長或者從新組合成咱們想要的效果。html

02_爲何用自定義控件

  系統控件沒法知足需求時,須要自定義控件。java

    1. 系統的控件在不一樣手機長得不同,咱們但願在不一樣手機實現相同的效果;
    2. 有些手機上的控件長得很差看,但願好看一些。
    3. 系統控件的功能有限,須要在基礎上增長功能。

03_怎麼用自定義控件-三種方式

1.使用系統控件,從新組合,實現自定義的效果,案例有:
       優酷環形菜單、廣告條循環滾動(Viewpager)、下拉菜單(spinner)、下拉框(PopupWindow、ListView)

2.本身定義一個類繼承View ,實現特定的效果,案例有:
       自定義開關按鈕、水波紋效果

3.本身定義一個類繼承ViewGroup,實現特定的效果,案例有:
       仿ViewPager的效果實現 、 仿網易側滑菜單

4.自定義屬性:給本身的控件,添加本身的屬性,經過demo瞭解系統解析屬性的過程,
並給上一個例子開關按鈕,添加新屬性。android

04_Android經常使用控件回顧

    Android自己提供了不少控件,如:
    文本控件    TextView和EditText;
    圖片控件    ImageView
    按鈕控件    Button和ImageButton
    進度條       ProgressBar
    單選按鈕    RadioButton和RadioGroup
    複選按鈕    CheckBox
    狀態開關按鈕ToggleButton
    時鐘控件    AnalogClock和DigitalClock
    日期與時間選擇控件DatePicker和TimePicker等。
          . . .

  使用原則儘可能使用系統的控件,在系統控件無法達到咱們的需求的時候才須要自定義控件。再定義控件會帶來工做量,例如修改bug.


  文本控件TextView 和EditText
    TextView 控件繼承自 View 類。TextView控件的功能是向用戶顯示文本內容,TextView不容許編輯。
    EditText控件繼承自 TextView。EditText與TextView 最大的不一樣是 EditText是能夠編輯的 


  圖片控件ImageView
    ImageView 控件負責顯示圖片,其圖片來源既能夠是資源文件的id,也能夠是Drawable對象或 Bitmap 對象,還能夠是 內容提供者(Content Provider)的Uri.

  


  按鈕控件Button 和 ImageButton
      Button控件繼承自 TextView 類,Button 的用法比較簡單,主要是爲 Button 設置一個點擊事件監聽器,並在編寫按鈕點擊事件的處理代碼。
    ImageButton 控件 繼承自 ImageView。
    ImageButton與Button相同之處:都用於響應按鈕的點擊事件
    不一樣之處:ImageButton只能顯示圖片;Button用於顯示文字  
    

  進度條ProgressBar
    ProgressBar繼承自 View,用於顯示正在運行的狀態。有兩種顯示形式:一種是環形顯示只用於顯示狀態,沒有具體的進度。第二種是水平顯示,能夠顯示具體  的進度。
    經過設置不一樣的Style顯示不一樣的樣式:
  style="?android:attr/progressBarStyleLarge"        環形樣式
  style="?android:attr/progressBarStyleHorizontal"    水平樣式

  


  單選按鈕 RadioButton 和複選按鈕 CheckBox
    CheckBox 和RadioButton 都繼承自CompoundButton,都只有選中和未選中兩種狀態,能夠經過checked屬性來設置。
    不一樣的是RadioButton 是單選按鈕,在一個RadioGroup中只能有一個RadioButton按鈕處於選中狀態;CheckBox 則能夠有多個按鈕被選中。  

    


  狀態開關按鈕ToggleButton
    ToggleButton 控件是繼承自 CompoundButton。ToggleButton 的狀態只能是選中和未選中,而且須要爲不一樣的狀態設置不一樣的顯示文本。除了繼承自父類的一  些屬性和方法以外,ToggleButton 也具備一些本身的屬性。

                           


  時鐘控件AnalogClock 和 DigitalClock
    AnalogClock繼承自 View,用於顯示模擬時鐘只顯示時針和分針。
    DigeitalClock 繼承自 TextView。用於顯示數字時鐘可精確到秒。 時鐘控件比較簡單,只須要在佈局文件中聲明控件便可。

                          



  日期選擇器 DatePicker 和時間選擇器 TimePicker

    DatePicker 繼承自FrameLayout類,日期選擇控件的主要功能是向用戶提供包含年、月、日的日期數據,並容許用戶對其修改。若是要捕獲這個修改,能夠  爲  DatePicker添加 onDateChangedListener 監聽器。
    TimePicker 一樣繼承自FrameLayout 類。時間選擇控件向用戶顯示一天中的時間,能夠爲24小時制,能夠爲AM/PM 制,並容許用戶進行修改。若是要捕獲用  戶的修改事件,須要爲TimePicker 添加OnTimeChangedListener 監聽器

                             
  知識連接:
    android WheelView組件(滑輪組件)的使用 : http://www.myexception.cn/android/1236819.html

    


  系統提供的控件雖然很豐富,可是,還遠遠不夠。有的時候咱們必需要本身定義控件來知足咱們的要求。下面的案例,詳細分析自定義控件的使用:git

2.優酷效果

  
  運行演示作好的優酷菜單效果,而且講解實現思路;由於如今優酷已經更換界面,引用此界面主要爲講解自定義控件實現的思想。 canvas

  優酷菜單就是使用系統控件,從新組合,來實現自定義的效果的。windows

  01_優酷佈局


    1_建立工程YukuMenuDemo,圖片所有拷貝到drawable-hdpi目錄下

    2_實現三個圓環-最裏面的圓環   框架

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <RelativeLayout
        android:id="@+id/level1"
        android:layout_centerHorizontal="true"
        android:layout_alignParentBottom="true"
        android:background="@drawable/level1"
        android:layout_width="100dip"
        android:layout_height="50dip" >
    </RelativeLayout>

</RelativeLayout>    

    3_實現三個圓環-中間園環     ide

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <RelativeLayout
        android:id="@+id/level2"
        android:layout_width="180dip"
        android:layout_height="90dip"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:background="@drawable/level2" >
    </RelativeLayout>

    <RelativeLayout
        android:id="@+id/level1"
        android:layout_width="100dip"
        android:layout_height="50dip"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:background="@drawable/level1" >
    </RelativeLayout>

</RelativeLayout>

    4_實現三個圓環-最外環工具

      這裏要說明下,相對佈局裏的是有焦點獲取前後要求的,level1放在最下面,才能先得到焦點。佈局

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <RelativeLayout
        android:id="@+id/level3"
        android:layout_width="280dip"
        android:layout_height="140dip"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:background="@drawable/level3" >
    </RelativeLayout>

    <RelativeLayout
        android:id="@+id/level2"
        android:layout_width="180dip"
        android:layout_height="90dip"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:background="@drawable/level2" >
    </RelativeLayout>

    <RelativeLayout
        android:id="@+id/level1"
        android:layout_width="100dip"
        android:layout_height="50dip"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:background="@drawable/level1" >
    </RelativeLayout>

</RelativeLayout>

    5_最裏環的的圖標

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <RelativeLayout
        android:id="@+id/level3"
        android:layout_width="280dip"
        android:layout_height="140dip"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:background="@drawable/level3" >
    </RelativeLayout>

    <RelativeLayout
        android:id="@+id/level2"
        android:layout_width="180dip"
        android:layout_height="90dip"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:background="@drawable/level2" >
    </RelativeLayout>

    <RelativeLayout
        android:id="@+id/level1"
        android:layout_width="100dip"
        android:layout_height="50dip"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:background="@drawable/level1" >

        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:src="@drawable/icon_home" />
    </RelativeLayout>

</RelativeLayout>

    6_中間環的圖標

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <RelativeLayout
        android:id="@+id/level3"
        android:layout_width="280dip"
        android:layout_height="140dip"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:background="@drawable/level3" >
    </RelativeLayout>

    <RelativeLayout
        android:id="@+id/level2"
        android:layout_width="180dip"
        android:layout_height="90dip"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:background="@drawable/level2" >

        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_margin="10dip"
            android:src="@drawable/icon_search" />

        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerHorizontal="true"
            android:layout_marginTop="5dip"
            android:src="@drawable/icon_menu" />

        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_alignParentRight="true"
            android:layout_margin="10dip"
            android:src="@drawable/icon_myyouku" />
    </RelativeLayout>

    <RelativeLayout
        android:id="@+id/level1"
        android:layout_width="100dip"
        android:layout_height="50dip"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:background="@drawable/level1" >

        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:src="@drawable/icon_home" />
    </RelativeLayout>

</RelativeLayout>

    7_最外環的圖標的左邊部分

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <RelativeLayout
        android:id="@+id/level3"
        android:layout_width="280dip"
        android:layout_height="140dip"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:background="@drawable/level3" >

        <ImageView
            android:id="@+id/channel1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_marginBottom="10dip"
            android:layout_marginLeft="10dip"
            android:src="@drawable/channel1" />

        <ImageView
            android:id="@+id/channel2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_above="@id/channel1"
            android:layout_alignLeft="@id/channel1"
            android:layout_marginLeft="20dip"
            android:layout_marginBottom="10dip"
            android:src="@drawable/channel2" />

        <ImageView
            android:id="@+id/channel3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_above="@id/channel2"
            android:layout_alignLeft="@id/channel2"
            android:layout_marginBottom="8dp"
            android:layout_marginLeft="35dp"
            android:src="@drawable/channel3" />

        <ImageView
            android:layout_marginTop="10dip"
            android:id="@+id/channel4"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerHorizontal="true"
            android:src="@drawable/channel4" />
    </RelativeLayout>

    <RelativeLayout
        android:id="@+id/level2"
        android:layout_width="180dip"
        android:layout_height="90dip"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:background="@drawable/level2" >

        ...............
    </RelativeLayout>

    <RelativeLayout
        android:id="@+id/level1"
        android:layout_width="100dip"
        android:layout_height="50dip"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:background="@drawable/level1" >

       ...............

    </RelativeLayout>

</RelativeLayout>

    8_最外環的圖標的右邊部分

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <RelativeLayout
        android:id="@+id/level3"
        android:layout_width="280dip"
        android:layout_height="140dip"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:background="@drawable/level3" >

        <ImageView
            android:id="@+id/channel1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_marginBottom="10dip"
            android:layout_marginLeft="10dip"
            android:src="@drawable/channel1" />

        <ImageView
            android:id="@+id/channel2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_above="@id/channel1"
            android:layout_alignLeft="@id/channel1"
            android:layout_marginBottom="10dip"
            android:layout_marginLeft="20dip"
            android:src="@drawable/channel2" />

        <ImageView
            android:id="@+id/channel3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_above="@id/channel2"
            android:layout_alignLeft="@id/channel2"
            android:layout_marginBottom="8dp"
            android:layout_marginLeft="35dp"
            android:src="@drawable/channel3" />

        <ImageView
            android:id="@+id/channel4"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerHorizontal="true"
            android:layout_marginTop="10dip"
            android:src="@drawable/channel4" />

        <ImageView
            android:id="@+id/channel7"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_alignParentRight="true"
            android:layout_marginBottom="10dip"
            android:layout_marginRight="10dip"
            android:src="@drawable/channel7" />

        <ImageView
            android:id="@+id/channel6"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_above="@id/channel7"
            android:layout_alignRight="@id/channel7"
            android:layout_marginBottom="10dip"
            android:layout_marginRight="20dip"
            android:src="@drawable/channel6" />

        <ImageView
            android:id="@+id/channel5"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_above="@id/channel6"
            android:layout_alignRight="@id/channel6"
            android:layout_marginBottom="10dip"
            android:layout_marginRight="35dip"
            android:src="@drawable/channel7" />
    </RelativeLayout>

         ................

         ................

</RelativeLayout>

 02_優酷代碼實現

    1_初始化三環的控件,並設置icom_menu和icom_menu的點擊事件

public class MainActivity extends Activity implements OnClickListener {

    private RelativeLayout level1;
    private RelativeLayout level2;
    private RelativeLayout level3;

    private ImageView icon_home;
    private ImageView icon_menu;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        level1 = (RelativeLayout) findViewById(R.id.level1);
        level2 = (RelativeLayout) findViewById(R.id.level2);
        level3 = (RelativeLayout) findViewById(R.id.level3);
        icon_home = (ImageView) findViewById(R.id.icon_home);
        icon_menu = (ImageView) findViewById(R.id.icon_menu);

        icon_home.setOnClickListener(this);
        icon_menu.setOnClickListener(this);
    }
    @Override
    public void onClick(View v) {
        switch (v.getId()) {
        case R.id.icon_home://相應home的點擊事件

            break;

        case R.id.icon_menu://相應menu的點擊事件
            break;
        }
    }

    2_三級菜單的顯示和隱藏

private boolean isLevel3Show = true;

@Override
    public void onClick(View v) {
        switch (v.getId()) {
        case R.id.icon_home:// 相應home的點擊事件

            break;

        case R.id.icon_menu:// 相應menu的點擊事件
            if (isLevel3Show) {
                Tools.hideView(level3);
                isLevel3Show = false;
            } else {
                Tools.showView(level3);
                isLevel3Show = true;
            }
            break;
        }
    }

    旋轉原理畫圖分析:    

  

    旋轉工具類代碼:  

/**
 * @author m
 *
 */
public class Tools {

    public static void hideView(View view) {
        /**
         * fromDegrees 從多少度開始
         * toDegrees 旋轉到度
         * pivotX 中心點x座標
         * pivotY 中心點y座標
         */
        RotateAnimation ra = new RotateAnimation(0, 180, view.getWidth()/2, view.getHeight());
        //播放時常
        ra.setDuration(500);
        //停留在播放完成狀態
        ra.setFillAfter(true);
        view.startAnimation(ra);
    }

    public static void showView(View view) {
        RotateAnimation ra = new RotateAnimation(180, 360, view.getWidth() / 2,
                view.getHeight());
        ra.setDuration(500);
        ra.setFillAfter(true);
        view.startAnimation(ra);
    }
}


    3_二級菜單的顯示和隱藏

@Override
    public void onClick(View v) {
        switch (v.getId()) {
        case R.id.icon_home:// 相應home的點擊事件
            if (isLevel2Show) {
                //若是二級菜單式顯示的,隱藏二級菜單
                Tools.hideView(level2);
                //判斷三級菜單的狀態,若是是顯示,同時也隱藏三級菜單
                if(isLevel3Show){
                    Tools.hideView(level3);
                }
                isLevel2Show = false;
            } else {
                //若是二級才能使隱藏的,那麼顯示二級菜單
                Tools.showView(level2);
                isLevel2Show = true;
            }

            break;

        case R.id.icon_menu:// 相應menu的點擊事件
            ..................
            break;
        }
    }

    4_設置延遲動畫setStartOffset()方法和代碼重構      

/**
 * @author m
 * 
 */
public class Tools {

    public static void hideView(View view) {
        hideView(view, 0);
    }

    public static void showView(View view) {
        showView(view, 0);
    }

    /**
     * 延遲顯示
     * 
     * @param view
     * @param i
     */
    public static void showView(View view, int i) {
        RotateAnimation ra = new RotateAnimation(180, 360, view.getWidth() / 2,
                view.getHeight());
        ra.setDuration(500);
        ra.setFillAfter(true);
        ra.setStartOffset(i);
        view.startAnimation(ra);
    }

    /**
     * 延遲隱藏
     * 
     * @param view
     * @param i
     *            延遲隱藏的時間
     */
    public static void hideView(View view, int i) {
        /**
         * fromDegrees 從多少度開 toDegrees 旋轉到度 pivotX x座標 pivotY y座標
         */
        RotateAnimation ra = new RotateAnimation(0, 180, view.getWidth() / 2,
                view.getHeight());
        // 播放時常
        ra.setDuration(500);
        // 停留在播放完成狀態
        ra.setFillAfter(true);
        ra.setStartOffset(i);
        view.startAnimation(ra);

    }
}

    5._監聽手機menu按鍵實現菜單隱藏和顯示

        多數安卓手機支持menu,但小米手機就不支持。經過觀察咱們知道,若是都顯示:點擊menu鍵,分別隱藏這三級菜單;若是沒顯示:點擊menu鍵,則顯示一二級菜單。

@Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_MENU) {

            if (isLevel1Show) {
                // 若是一級菜單式顯示的,那麼隱藏 一級菜單
                Tools.hideView(level1);
                isLevel1Show = false;
                // 同時判斷 隱藏二級、三級菜單
                if (isLevel2Show) {
                    Tools.hideView(level2, 200);
                    isLevel2Show = false;
                    if (isLevel3Show) {
                        Tools.hideView(level3, 300);
                        isLevel3Show = false;
                    }
                }
            } else {
                // 若是一級菜單式隱藏的,那麼就要顯示一級菜單
                Tools.showView(level1);
                isLevel1Show = true;
                // 同時要顯示二級菜單
                Tools.showView(level2,200);
                isLevel2Show = true;

            }

            return true;
        }
        return super.onKeyDown(keyCode, event);
    }

 03_優酷效果的完成和bug修復

    bug描述:一二三級菜單所有隱藏狀態,再點擊手機菜單位置,二三級菜單會顯示

    

    解決:用ViewGroup和View的區別來解決bug

 

/**
 * @author m
 * 
 */
public class Tools {

    public static void hideView(ViewGroup view) {
        hideView(view, 0);
    }

    public static void showView(ViewGroup view) {
        showView(view, 0);
    }

    /**
     * 延遲顯示
     * 
     * @param view
     * @param i
     */
    public static void showView(ViewGroup view, int startOffset) {
        RotateAnimation ra = new RotateAnimation(180, 360, view.getWidth() / 2,
                view.getHeight());
        ra.setDuration(500);
        ra.setFillAfter(true);
        ra.setStartOffset(startOffset);
        view.startAnimation(ra);

        // view.setVisibility(View.VISIBLE);
        // view.setEnabled(true);
     //遍歷孩子的個數
for (int i = 0; i < view.getChildCount(); i++) { view.getChildAt(i).setEnabled(true); } } /** * 延遲隱藏 * * @param view * @param i * 延遲隱藏的時間 */ public static void hideView(ViewGroup view, int startOffset) { /** * fromDegrees 從多少度開 toDegrees 旋轉到度 pivotX x座標 pivotY y座標 */ RotateAnimation ra = new RotateAnimation(0, 180, view.getWidth() / 2, view.getHeight()); // 播放時常 ra.setDuration(500); // 停留在播放完成狀態 ra.setFillAfter(true); ra.setStartOffset(startOffset); view.startAnimation(ra); // view.setVisibility(View.GONE); // view.setEnabled(false); for (int i = 0; i < view.getChildCount(); i++) { view.getChildAt(i).setEnabled(false); } } }

3.廣告條和首頁推薦

  


  1_廣告條ViewPage的介紹


      1_建立工程名:

        首頁影片推廣效果,包名爲:com.bokeyuan.viewpager,而且拷貝圖片到drawable-hdpi目錄

      2_寫佈局文件:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <android.support.v4.view.ViewPager
        android:id="@+id/viewpager"
        android:layout_width="match_parent"
        android:layout_height="200dip" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignBottom="@id/viewpager"
        android:background="#33000000"
        android:gravity="center_horizontal"
        android:orientation="vertical"
        android:padding="5dip" >

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="三個火槍手"
            android:textColor="#ffffff"
            android:textSize="18sp" />

        <LinearLayout
            android:id="@+id/ll_point_group"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="5dip"
            android:orientation="horizontal" >
        </LinearLayout>
    </LinearLayout>

</RelativeLayout>

      3.實例化ViewPager和關聯其源代碼:

        代碼實例化:

public class MainActivity extends Activity {
    
    private ViewPager viewpager;
    private LinearLayout ll_point_group;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        viewpager = (ViewPager) findViewById(R.id.viewpager);
        ll_point_group = (LinearLayout) findViewById(R.id.ll_point_group);
    }    

}

        關聯源代碼:
          1.刪除工程裏面的Android Depandencies,刪除後會報錯,不要理會。看下面

            

          2.添加libs目錄下的Android-support-v4.jar包
            選中-->右鍵-->build path-->add to build path

          3.關聯源代碼
            目錄:C:\android\adt-bundle-windows-x86_64-20130219\sdk\extras\android\support\v4\src\java
            點擊ViewPager類,出現圖標;

            

            你們對於v4包都已經很熟悉了,如今在新建android項目時,v4包是默認導入的。v7包出來沒多長時間,用的人也很少,主要對3.0如下版本

            提供ActionBar支持,以及SearchView,PopupMenu等控件的支持。由於一些開源框架已經實現對3.0如下版本ActionBar的支 持,因此v7包的

            使用意義也不是很大。

          知識拓展:

            若是jar包導入錯誤,怎麼修改呢?
          右鍵工程---->properties---->Java Build Path --->Libraries-->選擇android-support-v4.jar展開---->Editor--->External Folder

          4.ViewPager的原理
            
          能顯示不少頁面,者些頁面能夠是圖片也能夠是佈局文件。


      4_設置圖片資源ID和圖片標題集合和準備ImageView列表數據

  // 圖片資源ID
    private final int[] imageIds = { 
            R.drawable.a,
            R.drawable.b, 
            R.drawable.c,
            R.drawable.d,
            R.drawable.e };

    // 圖片標題集合
    private final String[] imageDescriptions = {
            "鞏俐不低俗,我就不能低俗",
            "撲樹又回來啦!再唱經典老歌引萬人大合唱", 
            "揭祕北京電影如何升級", 
            "樂視網TV版大派送", 
            "熱血屌絲的反殺" };



   //準備數據
        imageList = new ArrayList<ImageView>();
        for(int i=0;i<imageIds.length;i++){
            ImageView imageView = new ImageView(this);
            imageView.setBackgroundResource(imageIds[i]);                             imageList.add(imageView);
        }



      5_爲ViewPager設置適配器

private class MyPagerAdapter extends PagerAdapter {

        @Override
        public int getCount() {
            // 頁面或者圖片的總數
            return imageList.size();
        }

        /**
         * 功能:給ViewPager添加指定的view
         * container 就是ViewPager,其實就是容器。
         * position 具體頁面或者圖片的位置
         */
        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            System.out.println("instantiateItem=="+position);
            View view = imageList.get(position);
            container.addView(view);
            //返回的值,不必定是View ,也能夠是和View有關係的任意的Object
//            return super.instantiateItem(container, position);
            return view;
        }

        /**
         * 判斷某個page和object的關係
         * object 是 instantiateItem的返回值
         */
        @Override
        public boolean isViewFromObject(View view, Object object) {
//            if(view ==object){
//                return true;
//            }else{
//                return false;
//            }
            return view ==object;
            
        }

        /**
         * 銷燬指定位置上的View或者object
         */
        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
            System.out.println("destroyItem=="+position);
            container.removeView((View) object);
//            super.destroyItem(container, position, object);
        }

    }

 



    6_解決運行報錯
      選中項目--->右鍵--->Java Build Path --->
      order export--->勾選android-support-v4.jar--->千萬不要忘了clean
      


  2_廣告條基本功能

     1_根據不一樣圖片顯示不一樣描述信息

viewpager.setOnPageChangeListener(new OnPageChangeListener() {
            
            /**
             * 當頁面被選擇了回調
             * position 當前被顯示的頁面的位置:從0開始
             */
            @Override
            public void onPageSelected(int position) {
                                        tv_image_desc.setText(imageDescriptions[position]);    
        }
            /**
             * 當頁面滑動了調用該方法
             */
            @Override
            public void onPageScrolled(int position, float positionOffset,
                    int positionOffsetPixels) {            
            }
            /**
             * 當頁面狀態發送變化的調用防方法
             * 靜止--滑動
             * 滑動-靜止
             * 
             */
            @Override
            public void onPageScrollStateChanged(int state) {
            }
        });

    2.用shape資源定義點和背景
      建立drawable目錄裏面建立文件
      point_normal.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="oval" >
    <size   android:height="5dip"  android:width="5dip" />
    <solid android:color="#55000000"/>
</shape>

 

      point_focused.xml 

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="oval" >
    <size   android:height="5dip"  android:width="5dip" />
    <solid android:color="#aaffffff"/>
</shape>

      point_selsetor.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_enabled="true"  android:drawable="@drawable/point_focused" /> 
<item android:state_enabled="false"  android:drawable="@drawable/point_normal" /> 
</selector>

 

    3.代碼裏面添加指示點

for(int i=0;i<imageIds.length;i++){
            ImageView imageView = new ImageView(this);
            imageView.setBackgroundResource(imageIds[i]);
            imageViews.add(imageView);
            
            //添加指示點
            ImageView point = new ImageView(this);
            point.setBackgroundResource(R.drawable.point_selsetor);
            ll_point_group.addView(point);
            
            //默認狀況下,第一個小點enable爲true
            if(i ==0){
                point.setEnabled(true);
            }else{
                point.setEnabled(false);
            }

}


    4_設置改變指示點的狀態
      如字體加粗部分

/**
     * 上次的位置
     */
private int lastPointIndex;

viewpager.setOnPageChangeListener(new OnPageChangeListener() {
            
            /**
             * 當頁面被選擇了回調
             * position 當前被顯示的頁面的位置:從0開始
             */
            @Override
            public void onPageSelected(int position) {
                System.out.println("onPageSelected="+position);
                tv_image_desc.setText(imageDescriptions[position]);
                
                //設置指示點的狀態 enable 的狀態爲true或者爲false;
                ll_point_group.getChildAt(position).setEnabled(true); ll_point_group.getChildAt(lastPointIndex).setEnabled(false); lastPointIndex = position;
            }
            /**
             * 當頁面滑動了調用該方法
             */
            @Override
            public void onPageScrolled(int position, float positionOffset,
                    int positionOffsetPixels) {
                
            }
            /**
             * 但頁面狀態發送變化的調用防方法
             * 靜止--滑動
             * 滑動-靜止
             * 
             */
            @Override
            public void onPageScrollStateChanged(int state) {
                System.out.println("onPageScrollStateChanged===state=="+state);
            }
        });

      5.設置指示點的間距
        如字體加粗部分

for(int i=0;i<imageIds.length;i++){
            ImageView imageView = new ImageView(this);
            imageView.setBackgroundResource(imageIds[i]);
            imageViews.add(imageView);
            
            //添加指示點
            ImageView point = new ImageView(this);
            
            LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT, -2); params.leftMargin = 15; point.setLayoutParams(params);
            
            point.setBackgroundResource(R.drawable.point_selsetor);
            ll_point_group.addView(point);
            
            //默認狀況下,第一個小點enable爲true
            if(i ==0){
                point.setEnabled(true);
            }else{
                point.setEnabled(false);
            }
        }

        注意導入包的時候,當前控件放入什麼佈局就導入誰的LayoutParams的。

      6_設置能夠循環滑動

viewpager.setOnPageChangeListener(new OnPageChangeListener() {
            
            /**
             * 當頁面被選擇了回調
             * position 當前被顯示的頁面的位置:從0開始
             */
            @Override
            public void onPageSelected(int position) {
                int  myIndex = position % imageViews.size();
                System.out.println("onPageSelected="+position);
                tv_image_desc.setText(imageDescriptions[myIndex]); //設置指示點的狀態 enable 的狀態爲true或者爲false;
                ll_point_group.getChildAt(myIndex).setEnabled(true);
                
                ll_point_group.getChildAt(lastPointIndex).setEnabled(false);
                lastPointIndex = myIndex;
            }
            ..............................
        });
    }

    private class MyPagerAdapter extends PagerAdapter {

        @Override
        public int getCount() {
            //獲得數據的總數
//            return imageViews.size();
            return Integer.MAX_VALUE;
        }

        /**
         * 給ViewPager添加指定的View
         * container 是ViewPage,他是一個容器
         * position 要實例化的view的位置
         */
        @Override
        public Object instantiateItem(ViewGroup container, int position) {
//            System.out.println("instantiateItem=="+position);
            //實例化View
            View view = imageViews.get(position%imageViews.size());
            container.addView(view);
            //返回值,不必定要是View對象,也能夠是和View有關係的任意object
//            return super.instantiateItem(container, position);
            return view;
        }
        ......................
    }

 



      7_解決左滑沒有效果問題

//要求恰好是imageViews.size()的整數倍
int item = Integer.MAX_VALUE/2-Integer.MAX_VALUE/2%imageViews.size(); //讓ViewPager跳轉到指定的位置,應該保證是imageView.size()的整數倍
viewpager.setCurrentItem(item );
//11 和 101


  3_廣告條自動翻頁(自動循環播放)

     實現方式有多種方案:
      1.定時器 timer + Handler
      2.while true 循環 sleep  + Handler;
      3.ClockManger + Handler ;
      4.Handler
      咱們採用經常使用的方式Handler

/**
     * 是否自定滑動運行中
     */
    private boolean isRunning = false;
    
    private Handler handler = new Handler(){
        public void handleMessage(android.os.Message msg) {
            viewpager.setCurrentItem(viewpager.getCurrentItem()+1);
            if(isRunning){
                handler.sendEmptyMessageDelayed(0, 4000);
            }
            
        };
    };


在onCreate中寫上
isRunning = true;
handler.sendEmptyMessageDelayed(0, 2000);

建立onDestroy寫上
//頁面銷燬中止自動播放動畫
isRunning = false;

4.下拉框

    下拉框效果:
    在editText的右邊放置一個小箭頭的圖片,點擊圖片,在editText的下方彈出一個popupWindow,並對popupWindow進行一些設置即獲得想要的效果。
    

 

  1_新建一個工程:

      下拉框,把須要的圖片拷貝到工程中,包名:com.bokeyuan.popupwindow

  2_寫佈局文件

代碼以下

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <EditText
        android:id="@+id/et_input"
        android:paddingRight="40dip"
        android:layout_marginTop="20dip"
        android:layout_centerHorizontal="true"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/hello_world" />
    <ImageView 
        android:id="@+id/dowan_arrow"
        android:layout_alignRight="@id/et_input"
        android:layout_alignTop="@id/et_input"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="5dip"
        android:layout_marginRight="5dip"
        android:background="@drawable/down_arrow"/>

</RelativeLayout>

  3_實例化控件並準備數據

public class MainActivity extends Activity {
    private EditText et_input;
    private ImageView downArrow;
    
    /**
     * 裝數據的集合
     */
    private ArrayList<String> msgList;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        et_input = (EditText) findViewById(R.id.et_input);
        downArrow = (ImageView) findViewById(R.id.dowan_arrow);
        //準備數據
        msgList = new ArrayList<String>();
        for(int i=0;i<30;i++){
            msgList.add("aaaaaaaaaa"+i);
        }
    }
}

    

  4_設置向下箭頭點擊事件並實例化popupwindow&TODO簡介 

 

downArrow.setOnClickListener(this);

//浮懸的窗體
    private PopupWindow  popupWindow;
    @Override
    public void onClick(View v) {
        switch (v.getId()) {
        case R.id.dowan_arrow:
            if(popupWindow == null){
                popupWindow = new PopupWindow(this);
                //設置高和寬
                popupWindow.setWidth(et_input.getWidth());
                popupWindow.setHeight(200);
                //設置窗體的內容
                //TODO ListView 尚未初始化
                popupWindow.setContentView(listView);
                
            }
            popupWindow.showAsDropDown(et_input, 0, 0);
            
            break;

        default:
            break;
        }

    

  5_實例化ListView而且設置適配器


      在onCreate方法中實例化ListView

//實例化ListView
listView = new ListView(this);
listView.setAdapter(new MyAdapter());

      自定義適配器

class MyAdapter extends BaseAdapter{

        @Override
        public int getCount() {
            return msgList.size();
        }
        @Override
        public View getView(final int position, View convertView, ViewGroup parent) {
            View view;
            ViewHolder holder;
            if(convertView != null){
                view = convertView;
                holder = (ViewHolder) view.getTag();
            }else{
                view =  View.inflate(MainActivity.this, R.layout.list_popupwindow_item, null);
                holder = new ViewHolder();
                holder.iv_user = (ImageView) view.findViewById(R.id.iv_user);
                holder.tv_tilte = (TextView) view.findViewById(R.id.tv_tilte);
                holder.iv_delete = (ImageView) view.findViewById(R.id.iv_delete);
                view.setTag(holder);
            }
            holder.tv_tilte.setText(msgList.get(position));
            holder.iv_delete.setOnClickListener(new OnClickListener() {
                
                @Override
                public void onClick(View v) {
                    //1.把點擊的條在列表中移除
                    msgList.remove(position);
                    //2.更新數據
                    notifyDataSetChanged();
                }
            });            
            return view;
        }
        @Override
        public Object getItem(int position) {
            return null;
        }

        @Override
        public long getItemId(int position) {
            // TODO Auto-generated method stub
            return 0;
        }
        
    }
    
    class ViewHolder{
        ImageView iv_user;
        TextView tv_tilte;
        ImageView iv_delete;
    }

      每條佈局文件代碼list_popupwindow_item.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="55dip"
    android:gravity="center_vertical"
    android:padding="15dip" >

    <ImageView
        android:id="@+id/iv_user"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/user"
        android:padding="5dp" />

    <TextView
        android:id="@+id/tv_tilte"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:text="aaaaaaaaa1" />

    <ImageView
        android:id="@+id/iv_delete"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:background="@drawable/delete"
        android:padding="5dp" />

</RelativeLayout>

      演示運行看看效果

  6_ListView在低版本2.3的適配而且解決各個問題

      設置輸入框的寬爲200dip

<EditText
        android:id="@+id/et_input"
        android:paddingRight="40dip"
        android:layout_marginTop="20dip"
        android:layout_centerHorizontal="true"
        android:layout_width="200dip"
        android:layout_height="wrap_content"
        android:text="@string/hello_world" />

      解決按下變白的問題:    

listView = new ListView(this);
listView.setBackgroundResource(R.drawable.listview_background);
listView.setAdapter(new MyAdapter());

      解決點擊popupwindow外部,沒法消掉問題

popupWindow.setOutsideTouchable(true);

      設置選擇某一條,而且顯示在輸入框中

listView.setOnItemClickListener(new OnItemClickListener() {

            @Override
            public void onItemClick(AdapterView<?> parent, View view,
                    int position, long id) {
                et_input.setText(msgList.get(position));

            }
        });

      注意須要設置popupwindow的焦點才起做用

popupWindow.setFocusable(true);

      在setOnItemClickListener方法中消掉對話框

popupWindow.dismiss();

@Override
    public void onClick(View v) {
        switch (v.getId()) {
        case R.id.iv_down_arrow://點擊向下箭頭
            if(window == null){
                window = new PopupWindow(this);

//                window.setBackgroundDrawable(new ColorDrawable(color.transparent));
                window.setWidth(et_input.getWidth());
                window.setHeight(200);

                //TODO 設置popupWindow的內容
                window.setContentView(contentView);

//                window.setOutsideTouchable(true);
                //不必定要背景,主要是setFocusable要先執行,showAsDropDown後執行
                window.setFocusable(true);
            }
            window.showAsDropDown(et_input, 0, 0);
            break;

        default:
            break;
        }

    }

5.自定義開關按鈕

  1_自定義點擊開關按鈕

      繼承已有View實現自定義View

      經過對android原生控件的研究,能夠發現android中的控件都是繼承view類,如textView、ImageView等,經過重寫相關的方法來實現新的效果,經過這個咱們獲得兩點:
      咱們能夠在已有控件的基礎上,經過重寫相關方法來實現咱們的需求。
      繼承view類或viewgroup類,來建立咱們所須要的控件。通常來說,經過繼承已有的控件,來自定義控件要簡單一點。
      
      

      

    1_建立工程:

      開關按鈕,包名:com.itheima.togglebutton,並把圖片拷貝到工程中

    2_自定義類MyToggleButton繼承自View

實現三個構造方法
/**
 * 自定按鈕
 * @author afu
 */
public class MyToggleButton extends View {

    // 增長一個默認顯示樣式時候使用
    public MyToggleButton(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    // 在佈局文件中聲明view的時候,該方法有系統調用
    public MyToggleButton(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    // 在代碼中new實例化時調用
    public MyToggleButton(Context context) {
        super(context);
    }

}

 

在佈局文件中使用

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

<com.itheima.togglebutton.MyToggleButton
  android:layout_centerHorizontal="true"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</RelativeLayout>

 

 

    3_一個View從建立到顯示屏幕的步驟

      1.執行view構造方法,建立對象

      2.測量view大小
              onMeasure(int,int);來完成測量動做
        3.指定view的位置,子View只有建議權,父View纔有決定權;
           onLayout(boolean,int,int,int ,int);
           這個方法通常用不着,若是自定義繼承ViewGoup纔用到
        4.繪製view的內容
          onDraw(canvas);

    4_畫個矩形背景和圓形

package com.bokeyuan.togglebutton;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;

/**
 * 自定按鈕
 * @author m
 */
public class MyToggleButton extends View {
    
    /**
     * 一個View從建立到顯示屏幕上的主要步驟:
     * 1.執行view構造方法,建立對象
     * 2.測量view大小
     *  onMeasure(int,int);來完成測量動做
     * 3.指定view的位置,子View只有建議權,父View纔有決定權;
     * onLayout(boolean,int,int,int ,int);
     * 這個方法通常用不着,若是自定義ViewGoup纔用到
     * 4.繪製view的內容
     * onDraw(canvas);
     * 
     */
    
    private Paint paint;

    /**
     * 測量
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //設置當前view的測量大小
        setMeasuredDimension(100, 100);
    }
    /**
     * 繪製
     */
    @Override
    protected void onDraw(Canvas canvas) {
//        super.onDraw(canvas);
        //繪製顏色,能夠理解成背景顏色
        canvas.drawColor(Color.RED);
        //繪製圓形
        canvas.drawCircle(50, 50, 20, paint);
    }
    
    private void init(Context context) {
        paint = new Paint();
        paint.setColor(Color.GREEN);
        //設置抗鋸齒,讓邊緣圓滑,通常都會設置
        paint.setAntiAlias(true);
        
    }
    // 增長一個默認顯示樣式時候使用
    public MyToggleButton(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(context);
    }

    // 在佈局文件中聲明view的時候,該方法有系統調用
    public MyToggleButton(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    // 在代碼中new實例化時調用
    public MyToggleButton(Context context) {
        super(context);
        init(context);
    }
}

    5_畫按鈕背景

package com.bokeyuan.togglebutton;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ImageView;

/**
 * 自定按鈕
 * @author m
 */
public class MyToggleButton extends View {
    
    /**
     * 一個View從建立到顯示屏幕上的主要步驟:
     * 1.執行view構造方法,建立對象
     * 2.測量view大小
     *  onMeasure(int,int);來完成測量動做
     * 3.指定view的位置,子View只有建議權,父View纔有決定權;
     * onLayout(boolean,int,int,int ,int);
     * 這個方法通常用不着,若是自定義ViewGoup纔用到
     * 4.繪製view的內容
     * onDraw(canvas);
     * 
     */
    
    private Paint paint;
    private Bitmap backGroundBitmap;
    private Bitmap slideBitmap;
    private Context context;

    /**
     * 測量
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //設置當前view的測量大小
        setMeasuredDimension(backGroundBitmap.getWidth(), backGroundBitmap.getHeight());
    }
    /**
     * 繪製
     */
    @Override
    protected void onDraw(Canvas canvas) {
//        super.onDraw(canvas);
        //繪製顏色,能夠理解成背景顏色
//        canvas.drawColor(Color.RED);
        //繪製圓形
//        canvas.drawCircle(50, 50, 20, paint);
        canvas.drawBitmap(backGroundBitmap, 0, 0, paint);
    }
    
    private void init(Context context) {
        this.context = context;
        paint = new Paint();
        paint.setColor(Color.GREEN);
        //設置抗鋸齒,讓邊緣圓滑,通常都會設置
        paint.setAntiAlias(true);
        
        //初始化圖片-從資源文件中解析成Bitmap對象
        slideBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.slide_button);
        backGroundBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.switch_background);
        
    }
    // 增長一個默認顯示樣式時候使用
    public MyToggleButton(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(context);
    }

    // 在佈局文件中聲明view的時候,該方法有系統調用
    public MyToggleButton(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    // 在代碼中new實例化時調用
    public MyToggleButton(Context context) {
        super(context);
        init(context);
    }
    

}

    6_畫滑動按鈕

canvas.drawBitmap(slideBitmap, 45, 0, paint);

     分別設置0和30運行看看效果

    7_點擊時改變按鈕狀態

package com.bokeyuan.togglebutton;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ImageView;

/**
 * 自定按鈕
 * @author m
 */
public class MyToggleButton extends View implements  View.OnClickListener {
    
    /**
     * 一個View從建立到顯示屏幕上的主要步驟:
     * 1.執行view構造方法,建立對象
     * 2.測量view大小
     *  onMeasure(int,int);來完成測量動做
     * 3.指定view的位置,子View只有建議權,父View纔有決定權;
     * onLayout(boolean,int,int,int ,int);
     * 這個方法通常用不着,若是自定義ViewGoup纔用到
     * 4.繪製view的內容
     * onDraw(canvas);
     * 
     */
    
    private Paint paint;
    private Bitmap backGroundBitmap;
    private Bitmap slideBitmap;
    private Context context;
    /**
     * 距離左邊的距離
     */
    private float slideLeft;
    /**
     * 判斷當前開關狀態
     * true爲開
     * false爲關
     */
    private boolean curStata = false;

    /**
     * 測量
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //設置當前view的測量大小
        setMeasuredDimension(backGroundBitmap.getWidth(), backGroundBitmap.getHeight());
    }
    /**
     * 繪製
     */
    @Override
    protected void onDraw(Canvas canvas) {
//        super.onDraw(canvas);
        //繪製顏色,能夠理解成背景顏色
//        canvas.drawColor(Color.RED);
        //繪製圓形
//        canvas.drawCircle(50, 50, 20, paint);
        canvas.drawBitmap(backGroundBitmap, 0, 0, paint);
        //繪製滑動按鈕
        canvas.drawBitmap(slideBitmap, slideLeft, 0, paint);
    }
    
    private void init(Context context) {
        this.context = context;
        paint = new Paint();
        paint.setColor(Color.GREEN);
        //設置抗鋸齒,讓邊緣圓滑,通常都會設置
        paint.setAntiAlias(true);
        
        //初始化圖片-從資源文件中解析成Bitmap對象
        slideBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.slide_button);-
        backGroundBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.switch_background);
        
        setOnClickListener( MyToggleButton.this);
        
    }
    // 增長一個默認顯示樣式時候使用
    public MyToggleButton(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(context);
    }

    // 在佈局文件中聲明view的時候,該方法有系統調用
    public MyToggleButton(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    // 在代碼中new實例化時調用
    public MyToggleButton(Context context) {
        super(context);
        init(context);
    }
    
    @Override
    public void onClick(View v) {
        curStata = !curStata;
        flushState();
        
    }
    /**
     * 刷新狀態
     */
    private void flushState() {
        //設置距離左邊的距離
        if(curStata){
            slideLeft = backGroundBitmap.getWidth()-slideBitmap.getWidth();
        }else{
            slideLeft = 0;
        }
        
        /**
         * 刷新View,會致使當前View的onDraw方法執行
         */
        invalidate();
    }
}

  2_自定義滑動開關按鈕

    1_實現滑動效果

          實現思想,參照手機衛士中的拖動的原理

 /**
     * 第一次按下的x座標
     */
    int startX = 0;
    

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        super.onTouchEvent(event);
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN://按下
            //1.記錄第一次按下座標
            startX = (int) event.getRawX();

            break;
        case MotionEvent.ACTION_MOVE://滑動
            //2.來到新的座標
            int newX = (int) event.getRawX();
            //3.計算偏移量
            int dX = newX - startX;
            slideLeft += dX;
            //4.更新UI-onDraw方法便可--invalidate();
            invalidate();
            //5.從新記錄座標
            startX = (int) event.getRawX();
            break;
        case MotionEvent.ACTION_UP://離開

            break;

        default:
            break;
        }
        
        return true;
    }

    2_取消點擊事件,屏蔽非法滑動

public class MyToggleButton extends View implements OnClickListener {

    private Paint paint;

    /**
     * 一個View從建立到顯示到屏幕過程當中的步驟: 1.執行View的構造方法,實例化;一般在構造方法裏面加載資源 2.測量view對象
     * onMeasure(int,int) 3.指定View的位置 - 通常的View用不到,自定義包括其餘View進來這樣的控纔用到
     * onLayout(boolean,int,int,int,int) 4.繪製View對象 onDraw(canvas)
     * 
     */

    private Bitmap backgroundBitmap;
    private Bitmap slideBitmap;

    /**
     * 滑動圖片,距離左邊的距離
     */
    private float slideLeft;
    /**
     * 按鈕的狀態 false爲關閉 true爲開
     */
    private boolean curState = false;

    // 測量
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        // super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        // 設置測量值
        setMeasuredDimension(backgroundBitmap.getWidth(),
                backgroundBitmap.getHeight());
    }

    // 繪製
    @Override
    protected void onDraw(Canvas canvas) {
        // super.onDraw(canvas);
        // canvas.drawColor(Color.GREEN);
        // canvas.drawCircle(50, 50, 20, paint);
        canvas.drawBitmap(backgroundBitmap, 0, 0, paint);
        canvas.drawBitmap(slideBitmap, slideLeft, 0, paint);
    }
    /**
     * 第一次按下的x座標
     */
    int startX = 0;
    int maxLeft;
    

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        super.onTouchEvent(event);
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN://按下
            //1.記錄第一次按下座標
            startX = (int) event.getRawX();

            break;
        case MotionEvent.ACTION_MOVE://滑動
            //2.來到新的座標
            int newX = (int) event.getRawX();
            //3.計算偏移量
            int dX = newX - startX;
            slideLeft += dX;
            //4.更新UI-onDraw方法便可--invalidate();
 flushView(); //5.從新記錄座標
            startX = (int) event.getRawX();
            break;
        case MotionEvent.ACTION_UP://離開

            break;

        default:
            break;
        }
        
        return true;
    }

  // 刷新View的狀態,而且糾正非法滑動
    private void flushView() { if(slideLeft < 0){ slideLeft = 0; } if(slideLeft > maxLeft){ slideLeft = maxLeft; } //屏蔽非法滑動
 invalidate(); } private void init(Context context) {
        paint = new Paint();
        paint.setColor(Color.RED);
        // 設置抗鋸齒-使其變得光滑
        paint.setAntiAlias(true);
        // 加載資源圖片
        backgroundBitmap = BitmapFactory.decodeResource(getResources(),
                R.drawable.switch_background);
        slideBitmap = BitmapFactory.decodeResource(getResources(),
                R.drawable.slide_button);
        
        //滑動圖片距離左邊的距離
        maxLeft = backgroundBitmap.getWidth()-slideBitmap.getWidth(); // 設置點擊事件
//        setOnClickListener(this);
    }

    // 通常會在代碼中實例化
    public MyToggleButton(Context context) {
        super(context);
        init(context);
    }

    // 帶有兩個參數的構造方法,在佈局文件中使用的時候,就會回調
    public MyToggleButton(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    // 咱們須要設置默認的樣式風格的時候
    public MyToggleButton(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(context);
    }

    @Override
    public void onClick(View v) {
        curState = !curState;
 flushState();
    }

    // 刷新View的狀態
    private void flushState() {
        if (curState) {
            
            slideLeft = maxLeft;
        } else {
            slideLeft = 0;
        }
        flushView();     }
}

 

    3_處理滑動到一小半時時很差看的問題

      先畫圖分析

      
      代碼以下:

@Override
    public boolean onTouchEvent(MotionEvent event) {
        super.onTouchEvent(event);
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN://按下
            //1.記錄第一次按下座標
            startX = (int) event.getRawX();

            break;
        case MotionEvent.ACTION_MOVE://滑動
            //2.來到新的座標
            int newX = (int) event.getRawX();
            //3.計算偏移量
            int dX = newX - startX;
            slideLeft += dX;
            //4.更新UI-onDraw方法便可--invalidate();
            flushView();
            //5.從新記錄座標
            startX = (int) event.getRawX();
            break;
        case MotionEvent.ACTION_UP://離開
            /** * 當UP事件發生的時候,由按鈕的左邊距離(btn_left)肯定View的狀態; 當btn_left >= maxLeft/2 設置爲開狀態 當btn_left < maxLeft/2 設置爲 關閉狀態 */
            
            if(slideLeft >= maxLeft/2){ curState = true; }else{ curState = false; } flushState(); break;

        default:
            break;
        }
        
        return true;
    }

      恢復點擊事件
      演示會有bug

  3_ 解決點擊事件和滑動事件致使的bug

public class MyToggleButton extends View implements OnClickListener {

    private Paint paint;

    /**
     * 一個View從建立到顯示到屏幕過程當中的步驟: 1.執行View的構造方法,實例化;一般在構造方法裏面加載資源 2.測量view對象
     * onMeasure(int,int) 3.指定View的位置 - 通常的View用不到,自定義包括其餘View進來這樣的控纔用到
     * onLayout(boolean,int,int,int,int) 4.繪製View對象 onDraw(canvas)
     * 
     */

    private Bitmap backgroundBitmap;
    private Bitmap slideBitmap;

    /**
     * 滑動圖片,距離左邊的距離
     */
    private float slideLeft;
    /**
     * 按鈕的狀態 false爲關閉 true爲開
     */
    private boolean curState = false;

    // 測量
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        // super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        // 設置測量值
        setMeasuredDimension(backgroundBitmap.getWidth(),
                backgroundBitmap.getHeight());
    }

    // 繪製
    @Override
    protected void onDraw(Canvas canvas) {
        // super.onDraw(canvas);
        // canvas.drawColor(Color.GREEN);
        // canvas.drawCircle(50, 50, 20, paint);
        canvas.drawBitmap(backgroundBitmap, 0, 0, paint);
        canvas.drawBitmap(slideBitmap, slideLeft, 0, paint);
    }
    /**
     * 第一次按下的x座標
     */
    int startX = 0;
    /** * 最初的歷史位置 */
    int lastX = 0; /**
     * 滑動按鈕距離左邊的最大距離
     */
    int maxLeft;
    /** * 點擊事件是否可用 * true 可用 * false 不可用 */
    boolean isClickEnable = true;
    

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        super.onTouchEvent(event); switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN://按下
            //1.記錄第一次按下座標
            lastX = startX = (int) event.getRawX();
            isClickEnable = true;
            break;
        case MotionEvent.ACTION_MOVE://滑動
            //2.來到新的座標
            int newX = (int) event.getRawX();
            //3.計算偏移量
            int dX = newX - startX;
            slideLeft += dX;
            //4.更新UI-onDraw方法便可--invalidate();
            if(Math.abs(event.getRawX()-lastX)>5){ isClickEnable = false; }
            flushView();
            //5.從新記錄座標
            startX = (int) event.getRawX();
            break;
        case MotionEvent.ACTION_UP://離開
            
            if(!isClickEnable){ /**
                 *  當UP事件發生的時候,由按鈕的左邊距離(btn_left)肯定View的狀態;
                    當btn_left >= maxLeft/2 設置爲開狀態
                    當btn_left < maxLeft/2  設置爲 關閉狀態
                 */
                
                if(slideLeft >= maxLeft/2){
                    curState = true;
                }else{
                    curState = false;
                }
                flushState();
            }
            
            break;

        default:
            break;
        }
        
        return true;
    }

  // 刷新View的狀態,而且糾正非法滑動
    private void flushView() {
        if(slideLeft < 0){
            slideLeft = 0;
        }
        
        if(slideLeft > maxLeft){
            slideLeft = maxLeft;
        }
        //屏蔽非法滑動
        invalidate();
    }

    private void init(Context context) {
        paint = new Paint();
        paint.setColor(Color.RED);
        // 設置抗鋸齒-使其變得光滑
        paint.setAntiAlias(true);
        // 加載資源圖片
        backgroundBitmap = BitmapFactory.decodeResource(getResources(),
                R.drawable.switch_background);
        slideBitmap = BitmapFactory.decodeResource(getResources(),
                R.drawable.slide_button);
        
        //滑動圖片距離左邊的距離
        maxLeft = backgroundBitmap.getWidth()-slideBitmap.getWidth();

        // 設置點擊事件
        setOnClickListener(this);
    }

    // 通常會在代碼中實例化
    public MyToggleButton(Context context) {
        super(context);
        init(context);
    }

    // 帶有兩個參數的構造方法,在佈局文件中使用的時候,就會回調
    public MyToggleButton(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    // 咱們須要設置默認的樣式風格的時候
    public MyToggleButton(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(context);
    }

    @Override
    public void onClick(View v) {
        if(isClickEnable){
            curState = !curState;

            flushState();
        }
        
    }

    // 刷新View的狀態
    private void flushState() {
        if (curState) {
            
            slideLeft = maxLeft;
        } else {
            slideLeft = 0;
        }
        flushView();
    }
}
相關文章
相關標籤/搜索