編輯:關於android開發
Android系統中,繼承Android系統自帶的View或者ViewGroup控件或者系統自帶的控件,並在這基礎上增加或者重新組合成我們想要的效果。
系統控件無法滿足需求時,需要自定義控件。
1.使用系統控件,重新組合,實現自定義的效果,案例有:
優酷環形菜單、廣告條循環滾動(Viewpager)、下拉菜單(spinner)、下拉框(PopupWindow、ListView)
2.自己定義一個類繼承View ,實現特定的效果,案例有:
自定義開關按鈕、水波紋效果
3.自己定義一個類繼承ViewGroup,實現特定的效果,案例有:
仿ViewPager的效果實現 、 仿網易側滑菜單
4.自定義屬性:給自己的控件,添加自己的屬性,通過demo了解系統解析屬性的過程,
並給上一個例子開關按鈕,添加新屬性。
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顯示不同的樣式:
環形樣式
水平樣式
單選按鈕 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
系統提供的控件雖然很豐富,但是,還遠遠不夠。有的時候我們必須要自己定義控件來滿足我們的要求。下面的案例,詳細分析自定義控件的使用:
運行演示做好的優酷菜單效果,並且講解實現思路;因為現在優酷已經更換界面,引用此界面主要為講解自定義控件實現的思想。
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_實現三個圓環-中間園環
<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_實現三個圓環-最外環
<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>
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; } }
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); } }
@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; } }
/** * @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); } }
@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); }
/** * @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); } } }
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
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
實現方式有多種方案:
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);
下拉框效果:
在editText的右邊放置一個小箭頭的圖片,點擊圖片,在editText的下方彈出一個popupWindow,並對popupWindow進行一些設置即得到想要的效果。
下拉框,把需要的圖片拷貝到工程中,包名:com.bokeyuan.popupwindow
代碼如下
<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>
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); } } }
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; }
在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>
演示運行看看效果
設置輸入框的寬為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; } }
繼承已有View實現自定義View
通過對android原生控件的研究,可以發現android中的控件都是繼承view類,如textView、ImageView等,通過重寫相關的方法來實現新的效果,通過這個我們得到兩點:
我們可以在已有控件的基礎上,通過重寫相關方法來實現我們的需求。
繼承view類或viewgroup類,來創建我們所需要的控件。一般來講,通過繼承已有的控件,來自定義控件要簡單一點。
開關按鈕,包名:com.itheima.togglebutton,並把圖片拷貝到工程中
實現三個構造方法 /** * 自定按鈕 * @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>
1.執行view構造方法,創建對象
2.測量view大小
onMeasure(int,int);來完成測量動作
3.指定view的位置,子View只有建議權,父View才有決定權;
onLayout(boolean,int,int,int ,int);
這個方法一般用不著,如果自定義繼承ViewGoup才用到
4.繪制view的內容
onDraw(canvas);
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); } }
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); } }
canvas.drawBitmap(slideBitmap, 45, 0, paint);
分別設置0和30運行看看效果
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(); } }
實現思想,參照手機衛士中的拖動的原理
/** * 第一次按下的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; }
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(); } }
先畫圖分析
代碼如下:
@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
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(); } }
在android中使用SQLite數據庫 SQLite數據庫以其輕量、體積小等特點,使其在開發中運用的非常廣泛,在前面的博客中我也介紹過在Cocos2d-x中使用SQ
sqlite的基本使用,sqlite使用一:基本操作 1繼承SQLiteOpenHelper public class UserSqliteOpenHel
Android之genymotion模擬器安裝於配置,androidgenymotion 今天是雙休日,可憐沒人陪,只好一個人玩電腦了,之前別人一直給我推薦genymo
手把手帶你畫一個 時尚儀表盤 Android 自定義View 拿到美工效果圖,咱們程序員就得畫得一模一樣。 為了不被老板噴,只能多練啊。 聽說你覺得前面幾篇都so eas