Android自定义控件

android自定义控件

为什么我们需要自定义控件呢?

  • Android自身带的控件不能满足需求, 需要根据自己的需求定义控件.
  • 很多时候没有我们需要使用的控件,或者控件并不美观。
    Android本身提供了很多控件比如我们常用的有
      文本控件TextView和EditText;
      按钮控件Button和ImageButton
      状态开关按钮ToggleButton
      单选复选按钮RadioButton和RadioGroup
      单选按钮和复选按钮CheckBox
      图片控件ImageView
      时钟控件AnalogClock和DigitalClock
      进度条ProgressBar和日期与时间选择控件DatePicker和TimePicker等。

Android本身提供的基本控件

1 文本控件TextView 和EditText

  • TextView 控件继承自 View 类。TextView控件的功能是向用户显示文本内容同时可选择性让用户编辑文本。其中TextView不允许编辑。
  • EditText控件 EditText 控件继承自 TextView。EditText与TextView 最大的不同是 EditText是可以编辑的

2 按钮控件Button 和 ImageButton

  • Button控件继承自 TextView 类Button 的用法比较简单主要是为 Button 控件设置 View.OnClickListener.监听器并在监听器的实现代码中编写按钮按下事件的处理代码。
  • ImageButton 控件 ImageButton 继承自 ImageView。ImageButton 与Button最大的区别是ImageButton没有text 属性既按钮中将显示图片而不是文本。 ImageButton 控件中设置显示图片可以通过android:src 属性也可以通过setImageResurce(int ) 方法来实现

3 状态开关按钮ToggleButton

  • CheckBox 和RadioButton 都只有选中和未选中两种状态,可以通过checked属性来设置.
  • 不同的是RadioButton 是单选按钮,需要编制到一个RadioGroup中同一时刻一个RadioGroup中只能有一个按钮处于选中状态.
  • CheckBox和RadioButton 都是继承自 CompoundButton 中继承了一些成员.

4 图片控件ImageView

  • ImageView 控件负责显示图片,其图片来源既可以是资源文件的id,也可以是Drawable对象或 Bitmap 对象,还可以是 Content Provider 的Uri.

5 时钟控件AnalogClock 和 DigitalClock

  • AnalogClock继承自 ViewAnalogClock 控件显示模拟时钟只显示时针和分针
  • DigeitalClock 继承自 TextView。DigetalClock 显示数字时钟可精确到秒。 时钟控件比较简单只需要在布局文件中声明控件即可。

6 日期与时间选择控件DatePicker 和 TimePicker

  • DatePicker 继承自FrameLayout类日期选择控件的主要功能是向用户提供包含年、月、日的日期数据并允许用户对其进行选择。如果要捕获用户修改日期选择控件中数据的事件需要为DatePicker 添加 onDateChangedListener 监听器。
  • TimePicker 同样继承自FrameLayout 类。时间选择控件向用户显示一天中的时间可以为24小时制可以为AM/PM 制并允许用户进行选择。如果要捕获用户修改时间数据的事件便需要为TimePicker 添加OnTimeChangedListener 监听器

怎么自定义空间呢?

原理:继承已有控件实现自定义控件

  1. 通过对android本身提供的控件的代码进行研究,android中控件都是继承view类来实现,通过重写ondraw方法来绘制我们所需要的控件.通过这个我们得到两点提示:
  • 我们可以在已有的控件的基础上,通过重写相关方法来实现我们的需求.
  • 继承view类或viewgroup类,来绘制我们所需要的控件.一般来讲,通过继承已有的控件,来自定义控件要简单一点.
  1. 组合已有控件实现自定义控件
    组合已有控件实现自定义控件
  2. 完全自定义控件实现需求
    完全自定义控件实现需求
  3. 继承已有控件实现自定义控件
    继承已有控件实现自定义控件

自定义控件可以分为三大类型

1. 组合已有的控件实现

  1. 优酷菜单
  • 在xml布局里摆放好.
  • 给指定控件添加点击事件.
  • 根据业务逻辑,执行动画(旋转动画: 补间动画).
  • 菜单按钮的截获.
  1. 轮播图广告
  • 让图片滑动起来(ViewPager).
  • 让图片和文字,指示器对应起来.
  • 让轮播器无限循环
  1. 轮播器自动轮询
向右无限循环  
	0 -> 4	newPosition = position % 5  
	5 -> 0  
	6 -> 1  
	7 -> 2  
	8 -> 3  
	9 -> 4  
	10 -> 0  
向左无限循环  
设置到中间某个位置.
  1. 下拉选择框
  • Button或ImageButton等自带按钮功能的控件会抢夺所在Layout的焦点.导致其他区域点击不生效.在所在layout声明一个属性
android:descendantFocusability="blocksDescendants"	
  • popupwindow获取焦点, 外部可点击
// 设置点击外部区域, 自动隐藏
popupWindow.setOutsideTouchable(true); // 外部可触摸
popupWindow.setBackgroundDrawable(new BitmapDrawable()); // 设置空的背景, 响应点击事件		
popupWindow.setFocusable(true); //设置可获取焦点
ListView初始化
PopupWindow初始化

2. 完全自定义控件.(继承View, ViewGroup)

  • 自定义开关 (View)
  1. 写个类继承View, OK
  2. 拷贝包含包名的全路径到xml中, OK
  3. 界面中找到该控件, 设置初始信息, OK
  4. 根据需求绘制界面内容,OK
  5. 响应用户的触摸事件,OK
  6. 创建一个状态更新监听.OK
  7. 自定义属性.OK
  • 侧滑面板(ViewGroup)
  1. 在xml布局里摆放内容.
    侧滑面板页面布局
<TextView
 style="@style/style_bt_text"
 android:drawableLeft="@drawable/tab_news"
 android:text="新闻" />
        
<TextView
 style="@style/style_bt_text"
 android:drawableLeft="@drawable/tab_read"
 android:text="订阅" />
        
<TextView
 style="@style/style_bt_text"
 android:drawableLeft="@drawable/tab_local"
 android:text="本地" />
        
<TextView
 style="@style/style_bt_text"
 android:drawableLeft="@drawable/tab_ties"
 android:text="跟帖" />
        
<TextView
 style="@style/style_bt_text"
 android:drawableLeft="@drawable/tab_pics"
 android:text="图片" />
        
<TextView
 style="@style/style_bt_text"
 android:drawableLeft="@drawable/tab_ugc"
 android:text="话题" />
        
<TextView
 style="@style/style_bt_text"
 android:drawableLeft="@drawable/tab_vote"
 android:text="投票" />
<TextView
 style="@style/style_bt_text"
 android:drawableLeft="@drawable/tab_focus"
 android:text="聚合阅读" />        
</LinearLayout>
</ScrollView>
  1. 在自定义ViewGroup里, 进行measure测量, layout布局
  2. 响应用户的触摸事件
    触摸事件的传递机制
  3. int scrollX = (int) (downX - moveX);
  4. getScrollX()获取当前滚动到的位置
  5. 平滑动画
    侧滑面板
//1. 开始模拟数据

 scroller.startScroll(startX, 0, dx, 0, duration);
 invalidate();// 重绘界面 -> drawChild() -> computeScroll();

//2. 在computeScroll中不断获取模拟的数值

 @Override
 public void computeScroll() {
 super.computeScroll();
 if(scroller.computeScrollOffset()){
// true, 动画还没有结束
// 获取当前模拟的数据, 也就是要滚动到的位置
 int currX = scroller.getCurrX(); 
 scrollTo(currX, 0); // 滚过去
				
 invalidate(); // 重绘界面
}
}

3. 继承已有的控件实现(扩展已有的功能)

  • 包含下拉刷新功能的ListView
  1. 添加了自定义的头布局
    自定义的头布局
<FrameLayout
        android:layout_margin="5dp"
        android:layout_width="50dp"
        android:layout_height="50dp" >

        <ImageView
            android:id="@+id/iv_arrow"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:src="@drawable/common_listview_headview_red_arrow" />

        <ProgressBar
            android:id="@+id/pb"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:indeterminateDrawable="@drawable/shape_progress"
            android:visibility="invisible" />
    </FrameLayout>
  1. 默认让头布局隐藏setPadding.设置 -自身的高度
  2. ListView下拉的时候, 修改paddingTop, 让头布局显示出来
  3. 触摸动态修改头布局, 根据paddingTop.
    - paddingTop = 0 完全显示
    - paddingTop < 不完全显示 -64(自身高度)完全隐藏
    - paddingTop > 0 顶部空白
  1. 松手之后根据当前的paddingTop决定是否执行刷新
    - paddingTop < 0 不完全显示, 恢复
    - paddingTop >= 0 完全显示, 执行正在刷新...
/**
 * 根据状态更新头布局内容
 */
private void updateHeader() {
	switch (currentState) {
	case PULL_TO_REFRESH: // 切换回下拉刷新
	// 做动画, 改标题
	mArrowView.startAnimation(rotateDownAnim);
	mTitleText.setText("下拉刷新");
		break;
	case RELEASE_REFRESH: // 切换成释放刷新
	// 做动画, 改标题
	mArrowView.startAnimation(rotateUpAnim);
	mTitleText.setText("释放刷新");		
		break;
	case REFRESHING: // 刷新中...
	mArrowView.clearAnimation();
	mArrowView.setVisibility(View.INVISIBLE);
	pb.setVisibility(View.VISIBLE);
	mTitleText.setText("正在刷新中...");
			
if(mListener != null){
    mListener.onRefresh(); // 通知调用者, 让其到网络加载更多数据.
}			
		break;
		default:
		break;
}
}
posted @ 2016-06-22 16:12  ByteJava  阅读(719)  评论(0编辑  收藏  举报