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布局里摆放好.
  • 给指定控件添加点击事件.
  • 根据业务逻辑,执行动画(旋转动画: 补间动画).
  • 菜单按钮的截获.
    %E4%BC%98%E9%85%B7%E8%8F%9C%E5%8D%95.png
  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;
}
}

转载于:https://www.cnblogs.com/stephenhuashao/p/5607536.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值