【0058】自定义控件-2-完全自定义控件.(ViewGroup)-侧滑面板
1.侧滑面板效果

【说明】继承ViewGroup,因为其中包含有许多的小的条目,比如新闻、订阅等等;
2.布局
【说明】
(1)分为左面板和主面板
(2)使用帧布局;
(3)新知识点的使用:include的使用,在xml布局中包含另外一个布局(include)

2.1 左面板ScrollView 布局
2.1.1 背景图片的添加


【取色器】

2.1.2 单个textView的设置和图片添加

【抽取样式源码】
1 <resources> 2 3 <!-- 4 Base application theme, dependent on API level. This theme is replaced 5 by AppBaseTheme from res/values-vXX/styles.xml on newer devices. 6 --> 7 <style name="AppBaseTheme" parent="android:Theme.Light"> 8 <!-- 9 Theme customizations available in newer API levels can go in 10 res/values-vXX/styles.xml, while customizations related to 11 backward-compatibility can go here. 12 --> 13 </style> 14 15 <!-- Application theme. --> 16 <style name="AppTheme" parent="AppBaseTheme"> 17 <!-- All customizations that are NOT specific to a particular API-level can go here. --> 18 </style> 19 20 21 <style name="style_bt_text" parent="android:Widget.Holo.Light.TextView"> 22 <item name="android:background">@drawable/selector_menu_bt_bg</item> 23 <item name="android:clickable">true</item> 24 <item name="android:drawablePadding">10dp</item> 25 <item name="android:gravity">center_vertical</item> 26 <item name="android:padding">8dp</item> 27 <item name="android:textColor">#ADCFD6</item> 28 <item name="android:textSize">18sp</item> 29 <item name="android:layout_width">match_parent</item> 30 <item name="android:layout_height">wrap_content</item> 31 <item name="android:onClick">onTabClick</item> 32 </style> 33 </resources>
【左侧面板布局源码】
1 <?xml version="1.0" encoding="utf-8"?> 2 <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" 3 android:layout_width="240dp" 4 android:layout_height="match_parent" > 5 6 <LinearLayout 7 android:layout_width="240dp" 8 android:layout_height="match_parent" 9 android:background="@drawable/menu_bg" 10 android:orientation="vertical" > 11 12 <TextView 13 style="@style/style_bt_text" 14 android:drawableLeft="@drawable/tab_news" 15 android:text="新闻" /> 16 17 <TextView 18 style="@style/style_bt_text" 19 android:drawableLeft="@drawable/tab_read" 20 android:text="订阅" /> 21 22 <TextView 23 style="@style/style_bt_text" 24 android:drawableLeft="@drawable/tab_local" 25 android:text="本地" /> 26 27 <TextView 28 style="@style/style_bt_text" 29 android:drawableLeft="@drawable/tab_ties" 30 android:text="跟帖" /> 31 32 <TextView 33 style="@style/style_bt_text" 34 android:drawableLeft="@drawable/tab_pics" 35 android:text="图片" /> 36 37 <TextView 38 style="@style/style_bt_text" 39 android:drawableLeft="@drawable/tab_ugc" 40 android:text="话题" /> 41 42 <TextView 43 style="@style/style_bt_text" 44 android:drawableLeft="@drawable/tab_vote" 45 android:text="投票" /> 46 <TextView 47 style="@style/style_bt_text" 48 android:drawableLeft="@drawable/tab_focus" 49 android:text="聚合阅读" /> 50 51 </LinearLayout> 52 53 </ScrollView>
2.1.3 TextView的点击背景更改
【说明】默认是透明的,按下之后变为了蓝色

【说明】使用selector

【颜色的指定】




【布局当中颜色背景的添加】

2.1.4 左面板的整体布局的添加

【效果】

3. 去掉左侧面板的标题


4.添加别的图标
4.1 抽取样式



4.2 左侧面板源码
【layout_left_menu.xml源码】
1 <?xml version="1.0" encoding="utf-8"?> 2 <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" 3 android:layout_width="240dp" 4 android:layout_height="match_parent" > 5 6 <LinearLayout 7 android:layout_width="240dp" 8 android:layout_height="match_parent" 9 android:background="@drawable/menu_bg" 10 android:orientation="vertical" > 11 12 <TextView 13 style="@style/style_bt_text" 14 android:drawableLeft="@drawable/tab_news" 15 android:text="新闻" /> 16 17 <TextView 18 style="@style/style_bt_text" 19 android:drawableLeft="@drawable/tab_read" 20 android:text="订阅" /> 21 22 <TextView 23 style="@style/style_bt_text" 24 android:drawableLeft="@drawable/tab_local" 25 android:text="本地" /> 26 27 <TextView 28 style="@style/style_bt_text" 29 android:drawableLeft="@drawable/tab_ties" 30 android:text="跟帖" /> 31 32 <TextView 33 style="@style/style_bt_text" 34 android:drawableLeft="@drawable/tab_pics" 35 android:text="图片" /> 36 37 <TextView 38 style="@style/style_bt_text" 39 android:drawableLeft="@drawable/tab_ugc" 40 android:text="话题" /> 41 42 <TextView 43 style="@style/style_bt_text" 44 android:drawableLeft="@drawable/tab_vote" 45 android:text="投票" /> 46 <TextView 47 style="@style/style_bt_text" 48 android:drawableLeft="@drawable/tab_focus" 49 android:text="聚合阅读" /> 50 51 </LinearLayout> 52 53 </ScrollView>
【colors.xml源码】
1 <?xml version="1.0" encoding="utf-8"?> 2 <resources> 3 4 <color name="bt_bg_pressed">#33ADCFD6</color> 5 6 </resources>
【styles.xml新增的源码】
1 2 <style name="style_bt_text" parent="android:Widget.Holo.Light.TextView"> 3 <item name="android:background">@drawable/selector_menu_bt_bg</item> 4 <item name="android:clickable">true</item> 5 <item name="android:drawablePadding">10dp</item> 6 <item name="android:gravity">center_vertical</item> 7 <item name="android:padding">8dp</item> 8 <item name="android:textColor">#ADCFD6</item> 9 <item name="android:textSize">18sp</item> 10 <item name="android:layout_width">match_parent</item> 11 <item name="android:layout_height">wrap_content</item> 12 <item name="android:onClick">onTabClick</item> 13 </style>
5.主面板布局的实现
5.1 布局中的线的添加



5.2 主面板布局的效果

【layout_main_content.xml主面板的源码】
1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent" 5 android:background="#FFF" 6 android:orientation="vertical" > 7 8 <LinearLayout 9 android:layout_width="match_parent" 10 android:layout_height="wrap_content" 11 android:background="@drawable/top_bar_bg" 12 android:orientation="horizontal" > 13 14 <ImageButton 15 android:id="@+id/ib_back" 16 android:layout_width="wrap_content" 17 android:layout_height="wrap_content" 18 android:background="@null" 19 android:src="@drawable/main_back" /> 20 21 <View 22 android:layout_width="1dp" 23 android:layout_height="match_parent" 24 android:background="@drawable/top_bar_divider" /> 25 26 <TextView 27 android:layout_width="match_parent" 28 android:layout_height="wrap_content" 29 android:layout_gravity="center_vertical" 30 android:layout_marginLeft="10dp" 31 android:text="黑马新闻" 32 android:textColor="#FFF" 33 android:textSize="24sp" /> 34 </LinearLayout> 35 36 <TextView 37 android:layout_width="match_parent" 38 android:layout_height="match_parent" 39 android:gravity="center" 40 android:text="钓鱼岛是中国的! 苍老师才是世界的." 41 android:textSize="26dp" /> 42 43 </LinearLayout>
【activity_main.xml源码】使用include关键字,可以包含别的布局;
1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 2 xmlns:tools="http://schemas.android.com/tools" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent" 5 tools:context=".MainActivity" > 6 7 <com.itheima74.sliding.ui.SlideMenu 8 android:id="@+id/sm" 9 android:layout_width="match_parent" 10 android:layout_height="match_parent" > 11 12 <include layout="@layout/layout_left_menu"/> 13 14 <include layout="@layout/layout_main_content"/>" 15 16 </com.itheima74.sliding.ui.SlideMenu> 17 18 </RelativeLayout>
6. 布局的层级关系
【使用帧布局的层级关系】主面板将左侧面板进行了覆盖;

【解决方法】需要使用ViewGroup将左侧面板放到显示的屏幕的外边;



【注意】此处没有调用 onDraw()方法;

6.1 onMeasure方法
【onMeasure】测量孩子的宽高
【找到孩子】首先在测量孩子的位置的时候需要找到孩子,孩子本身就是一个集合了,如第一个左侧面就是0号位;第二个主面板就是1号位;


6.2 onLayout方法的书写
【说明】如果没有经过摆放的效果是空白的,就比如家里的布局测量好之后,家具没有摆放;

【控件摆放的坐标位置的确定】


【源码】
1 /** 2 * changed: 当前控件的尺寸大小, 位置 是否发生了变化 3 * left:当前控件 左边距 4 * top:当前控件 顶边距 5 * right:当前控件 右边界 6 * bottom:当前控件 下边界 7 */ 8 @Override 9 protected void onLayout(boolean changed, int l, int t, int r, int b) { 10 11 // 摆放内容, 左面板 12 View leftMenu = getChildAt(0); 13 leftMenu.layout(-leftMenu.getMeasuredWidth(), 0, 0, b); 14 15 // 主面板 16 getChildAt(1).layout(l, t, r, b); 17 }
7.触摸事件
7.1 触摸事件的返回值的确定
【说明】如果使用的已有控件的组合,则返回值是super,因为要使得原来的已有控件生效;
如果完全自定义的控件,则返回值是true;

7.2 scrollTo&scrollBy滚动内容
7.2.1 srollTo 和srollBy原理


7.2.2 完成滑动事件

7.2.3 限定边界
【说明】在面板进行滑动的时候,左侧面板会超出左边界,主面板会超出右边界;需要进行限定;

8. 界面跳转的实现(方法1)




9. 平滑动画的实现scroller(方法2)
9.1 scroller对象的创建
【说明】在构造方法中创建,为了创建一份对象;

9.2 源码

【源码】
1 /** 2 * 根据当前的状态, 执行 关闭/开启 的动画 3 */ 4 private void updateCurrentContent() { 5 int startX = getScrollX(); 6 int dx = 0; 7 // 平滑滚动 8 if(currentState == MENU_STATE){ 9 // 打开菜单 10 // scrollTo(-getChildAt(0).getMeasuredWidth(), 0); 11 // dx = 结束位置(-240) - 开始位置(-200) = -40 12 // dx = 0 - (-10) = 10 13 14 dx = -getChildAt(0).getMeasuredWidth() - startX; 15 16 } else { 17 // 恢复主界面 18 // scrollTo(0, 0); 19 20 dx = 0 - startX; 21 } 22 23 // startX: 开始的x值 24 // startY: 开始的y值 25 // dx: 将要发生的水平变化量. 移动的x距离 26 // dy: 将要发生的竖直变化量. 移动的y距离 27 // duration : 数据模拟持续的时长 28 29 // 1. 开始平滑的数据模拟 30 int duration = Math.abs(dx * 2); // 0 -> 1200 31 scroller.startScroll(startX, 0, dx, 0, duration); 32 33 // - 200 -> -240 34 // - 201 -> -202 -> -203 .... -236 -> -240 35 36 invalidate();// 重绘界面 -> drawChild() -> computeScroll(),下面的方法会被调用; 37 } 38 39 //2. 维持动画的继续 40 @Override 41 public void computeScroll() { 42 super.computeScroll(); 43 if(scroller.computeScrollOffset()){ // 直到duration事件以后, 结束 44 // true, 动画还没有结束 45 // 获取当前模拟的数据, 也就是要滚动到的位置 46 int currX = scroller.getCurrX(); 47 System.out.println("currX: " + currX); 48 scrollTo(currX, 0); // 滚过去 49 50 invalidate(); // 重绘界面-> drawChild() -> computeScroll();循环 51 } 52 }
10 添加开关功能
10.1 功能描述

10.2 源码




11. 触摸事件的截获

11.1 按钮按下的拦截机制的原理
【说明】在FrameLayout的布局中进行事件拦截的判断,避免事件在下面的按钮中事件不再返回;


11.2 源码

1 2 3 /** 4 * 拦截判断 5 */ 6 @Override 7 public boolean onInterceptTouchEvent(MotionEvent ev) { 8 9 switch (ev.getAction()) { 10 case MotionEvent.ACTION_DOWN: 11 downX = ev.getX(); 12 downY = ev.getY(); 13 break; 14 case MotionEvent.ACTION_MOVE: 15 16 float xOffset = Math.abs(ev.getX() - downX); 17 float yOffset = Math.abs(ev.getY() - downY); 18 19 if(xOffset > yOffset && xOffset > 5){ // 水平方向超出一定距离时,才拦截;细节:5dp定义是因为在手指可能轻轻的左右滑动,也要响应滑动事件; 20 return true; // 拦截此次触摸事件, 界面的滚动 拦截事件的核心 21 } 22 23 break; 24 case MotionEvent.ACTION_UP: 25 26 break; 27 28 default: 29 break; 30 } 31 return super.onInterceptTouchEvent(ev); 32 } 33 34 }
浙公网安备 33010602011771号