我们先实现单个按钮,为了复用,不管单选还是复选按钮都是使用同一个类来实现,为了区别单选还是复选,我们用一个自定义枚举类型CheckButtonStyle属性style来区别,当其值设置为CheckButtonStyleDefault或CheckButtonStyleBox时,为复选按钮:
当其值设为CheckButtonStyleRadio时,为单选按钮:
当按钮在选中/反选状态间切换时,文字左边的图片自动转换。
整个控件是由一个ImageView、一个Label、一个BOOL变量及其他变量组成,.h文件如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
typedef enum { CheckButtonStyleDefault = 0 , CheckButtonStyleBox = 1 , CheckButtonStyleRadio = 2 } CheckButtonStyle; #import <Foundation/Foundation.h> @interface CheckButton : UIControl { //UIControl* control; UILabel * label ; UIImageView * icon ; BOOL checked ; id value , delegate ; CheckButtonStyle style ; NSString * checkname ,* uncheckname ; // 勾选/反选时的图片文件名 } @property ( retain , nonatomic ) id value,delegate; @property ( retain , nonatomic )UILabel* label; @property ( retain , nonatomic )UIImageView* icon; @property ( assign )CheckButtonStyle style; -( CheckButtonStyle )style; -( void )setStyle:( CheckButtonStyle )st; -( BOOL )isChecked; -( void )setChecked:( BOOL )b; @end
具体实现如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
#import "CheckButton.h" @implementation CheckButton @synthesize label,icon,value,delegate; -( id )initWithFrame:( CGRect ) frame { if ( self =[ super initWithFrame : frame ]) { icon =[[ UIImageView alloc ] initWithFrame : CGRectMake ( 10 , 0 , frame . size . height , frame . size . height )]; [ self setStyle : CheckButtonStyleDefault ]; // 默认风格为方框(多选)样式 //self.backgroundColor=[UIColor grayColor]; [ self addSubview : icon ]; label =[[ UILabel alloc ] initWithFrame : CGRectMake ( icon . frame . size . width + 24 , 0 , frame . size . width - icon . frame . size . width - 24 , frame . size . height )]; label . backgroundColor =[ UIColor clearColor ]; label . font =[ UIFont fontWithName : @"Arial" size : 20 ]; label . textColor =[ UIColor colorWithRed : 0xf9 / 255.0 green : 0xd8 / 255.0 blue : 0x67 / 255.0 alpha : 1 ]; label . textAlignment = UITextAlignmentLeft ; [ self addSubview : label ]; [ self addTarget : self action : @selector ( clicked ) forControlEvents : UIControlEventTouchUpInside ]; } return self ; } -( CheckButtonStyle )style{ return style ; } -( void )setStyle:( CheckButtonStyle )st{ style =st; switch ( style ) { case CheckButtonStyleDefault : case CheckButtonStyleBox : checkname = @"checked.png" ; uncheckname = @"unchecked.png" ; break ; case CheckButtonStyleRadio : checkname = @"radio.png" ; uncheckname = @"unradio.png" ; break ; default : break ; } [ self setChecked : checked ]; } -( BOOL )isChecked{ return checked ; } -( void )setChecked:( BOOL )b{ if (b!= checked ){ checked =b; } if ( checked ) { [ icon setImage :[ UIImage imageNamed : checkname ]]; } else { [ icon setImage :[ UIImage imageNamed : uncheckname ]]; } } -( void )clicked{ [ self setChecked :! checked ]; if ( delegate != nil ) { SEL sel= NSSelectorFromString ( @"checkButtonClicked" ); if ([ delegate respondsToSelector :sel]){ [ delegate performSelector :sel]; } } } -( void )dealloc{ value = nil ; delegate = nil ; [ label release ]; [ icon release ]; [ super dealloc ]; } @end
使用CheckButton类很简单,构造、设置标签文本等属性,然后addSubview:
1 2 3 4 5
CheckButton * cb=[[ CheckButton a lloc ] initWithFrame : CGRectMake ( 20 , 60 , 260 , 32 )]; cb. label . text = @"checkbutton1" ; cb. value =[[ NSNumber alloc ] initWithInt : 18 ]; cb. style = CheckButtonStyleDefault ; [ self . view addSubview :cb];
二、单选按钮组的实现
复选按钮无所谓“组”的概念,单选按钮则不同。在同一个组中,单选按钮只允许同时选择一个按钮,不能选多个,因此我们要实现一个单选按钮组的类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
#import <Foundation/Foundation.h> #import "CheckButton.h" @interface RadioGroup : NSObject { NSMutableArray * children ; NSString * text ; id value ; } @property ( readonly )NSString* text; @property ( readonly ) id value; -( void )add:( CheckButton *)cb; -( void )checkButtonClicked:( id )sender; @end #import "RadioGroup.h" @implementation RadioGroup @synthesize text,value; -( id )init{ if ( self =[ super init ]){ children =[[ NSMutableArray alloc ] init ]; } return self ; } -( void )add:( CheckButton *)cb{ cb. delegate = self ; if (cb. checked ) { text =cb. label . text ; value =cb. value ; } [ children addObject :cb]; } -( void )checkButtonClicked:( id )sender{ CheckButton * cb=( CheckButton *)sender; if (!cb. checked ) { // 实现单选 for ( CheckButton * each in children ){ if (each. checked ) { [each setChecked : NO ]; } } [cb setChecked : YES ]; // 复制选择的项 text =cb. label . text ; value =cb. value ; } NSLog ( @"text:%@,value:%d" , text ,[( NSNumber *) value intValue ]); } -( void )dealloc{ [ text release ]; value = nil ; [ children release ]; [ super dealloc ]; } @end
单选按钮组在ViewController中的使用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
-( id )initWithNibName:( NSString *)nibNameOrNil bundle:( NSBundle *)nibBundleOrNil{ if ( self =[ super initWithNibName :nibNameOrNil bundle :nibBundleOrNil]){ // 单选按钮组 rg =[[ RadioGroup alloc ] init ]; // 第 1 个单选按钮 CheckButton * cb=[[ CheckButton alloc ] initWithFrame : CGRectMake ( 20 , 60 , 260 , 32 )]; // 把单选按钮加入按钮组 [ rg add :cb]; cb. label . text = @"★" ; cb. value =[[ NSNumber alloc ] initWithInt : 1 ]; // 把按钮设置为单选按钮样式 cb. style = CheckButtonStyleRadio ; // 加入视图 [ self . view addSubview :cb]; [cb release ]; //add 后,会自动持有,可以释放 // 第 2 个单选按钮 cb=[[ CheckButton alloc ] initWithFrame : CGRectMake ( 20 , 100 , 260 , 32 )]; [ rg add :cb]; cb. label . text = @"★★" ; cb. value =[[ NSNumber alloc ] initWithInt : 2 ]; cb. style = CheckButtonStyleRadio ; [ self . view addSubview :cb]; [cb release ]; // 第 3 个单选按钮 cb=[[ CheckButton alloc ] initWithFrame : CGRectMake ( 20 , 140 , 260 , 32 )]; // 各种属性必须在 [rg addv] 之前设置,否则 text 和 value 不会被 populate cb. checked = YES ; cb. label . text = @"★★★" ; cb. value =[[ NSNumber alloc ] initWithInt : 3 ]; cb. style = CheckButtonStyleRadio ; [ self . view addSubview :cb]; [ rg add :cb]; // 属性设置完之后再 add [cb release ]; // 第 4 个单选按钮 cb=[[ CheckButton alloc ] initWithFrame : CGRectMake ( 20 , 180 , 260 , 32 )]; [ rg add :cb]; cb. label . text = @"★★★★" ; cb. value =[[ NSNumber alloc ] initWithInt : 4 ]; cb. style = CheckButtonStyleRadio ; [ self . view addSubview :cb]; [cb release ]; // 第 5 个单选按钮 cb=[[ CheckButton alloc ] initWithFrame : CGRectMake ( 20 , 220 , 260 , 32 )]; [ rg add :cb]; cb. label . text = @"★★★★★" ; cb. value =[[ NSNumber alloc ] initWithInt : 5 ]; cb. style = CheckButtonStyleRadio ; [ self . view addSubview :cb]; [cb release ]; } return self ; }
运行效果:
原文作者:颐和园
原文链接:http://blog.csdn.net/kmyhy/archive/2011/01/18/6149996.aspx
public class HelloActivity extends Activity { ProgressDialog dlg = null; Handler mHandler = new Handler(); @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); dlg = new ProgressDialog(this); dlg.show(); //HelloActivity.this.finish();//---------------1 会立刻调用onDestory(); //java.lang.IllegalArgumentException: View not attached to window manager mHandler.postDelayed(new Runnable() { @Override public void run() { HelloActivity.this.finish();//-----2 dlg.cancel(); //WindowManager.removeview(HelloActivity, dlg); } }, 1000); setContentView(R.layout.hello_activity); } @Override public void onDestroy(){ super.onDestroy(); Log.d("yzy","activity....finish....."); } }
如果在1的位置finish.会报异常 view not attach to the windowmanager,这个很好理解。
如果在2的位置finish不会有任何问题,而且调用onDestory();
疑惑中........................................难道finish是个耗时操作,是个异步操作?
于是我2 的下面加了一行SystemClock.sleep(1000); 可是 第二种情况dlg.cancel()还是不报错?
真心不懂了!
监听器:
监听器 方法 内容 OnClickListener onClick 监听点击事件(点击或按下导航键) OnClickListener onLongClick 监听长按事件(保持点击或按住导航键) OnClickListener onKey 监听物理按件(点击或松开物理导航键,上下左右键) OnTouchListener onTouch 监听触摸事件(点击滑动弹起等)
设置监听器:
方法一:定义一个OnClickListener类的实例,并使用setOnClickListener等绑定监听器。
方法二:用Activity来实现OnClickListener接口。
其中第一种通常用匿名内部类或者内部类来实现。而第二种更加简洁,更加高效,特别是在很多空间需要添加监听器的情况下。
界面:
<Button android:id="@+id/button" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="MyButton" /> <TextView android:id="@+id/textview" android:layout_width="fill_parent" android:layout_height="wrap_content" />
在onLongClick中,返回值必须为true;消费概念:当时间完成对一个view的操作后,只需要返回true,表示该控件已经被消费了,后面的时间就不会被调用了。
ACTION_DOWN 按下
ACTION_MOVE 滑动
ACTION_UP 弹起
ACTION_DOWN为起始事件,如果调用了其他两个方法,这个是肯定先被调用。
package example.first; import android.app.Activity; import android.os.Bundle; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.View; import android.view.View.OnClickListener; import android.view.View.OnLongClickListener; import android.widget.Button; import android.widget.TextView; public class MainActivity extends Activity { private Button bt; private TextView tv; @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); tv=(TextView)findViewById(R.id.textview); bt=(Button)findViewById(R.id.button); //匿名内部类作为监听器 bt.setOnClickListener(new OnClickListener(){ @Override public void onClick(View arg0) { // TODO Auto-generated method stub tv.setText("你点击了button"); } }); bt.setOnLongClickListener(new OnLongClickListener(){ @Override public boolean onLongClick(View arg0) { // TODO Auto-generated method stub tv.setText("你长按了button"); return true; //注意这里必须return true } }); } @Override public boolean onKeyDown(int keyCode,KeyEvent event){ switch(keyCode){ case KeyEvent.KEYCODE_DPAD_UP:tv.setText("你按下了上方向键");//监听按下上方向键 break; case KeyEvent.KEYCODE_DPAD_DOWN:tv.setText("你按下了下方向键"); } return super.onKeyDown(keyCode, event); } @Override public boolean onKeyUp(int keyCode,KeyEvent event){ switch(keyCode){ case KeyEvent.KEYCODE_DPAD_UP:tv.setText("你松开了了上方向键"); break; case KeyEvent.KEYCODE_DPAD_DOWN:tv.setText("你松开了下方向键"); } return super.onKeyUp(keyCode, event); } public boolean onTouchEvent(MotionEvent event){ int x=(int)event.getX(); int y=(int)event.getY(); switch(event.getAction()){ case MotionEvent.ACTION_MOVE:tv.setText("你滑动了屏幕"); break; case MotionEvent.ACTION_DOWN:tv.setText("你点击的屏幕坐标为" +Integer.toString(x)+","+Integer.toString(y));//取得点击的坐标 break; case MotionEvent.ACTION_UP:tv.setText("你离开屏幕的坐标为" +Integer.toString(x)+","+Integer.toString(y));//取得松开时的坐标 break; } return true; //最好是return true } }
运行效果:
Button效果;状态列表(statelist实现)
根标签setector
一个item定义一种状态(按下 选中 无焦点状态)
item下有shape标签,用来定义控件的显示效果,含有gradient,stoke,corners等子标签分别表示不同的效果。
在stoke圆角标签中,分别指定每个角的弧度时,bottomRightRadius代表左下角,bottomLeftRadius代表右下角。