【0093】【项目实战】-【谷歌电子市场】-【05】【应用详情页-截图模块开发】【应用详情页-描述模块开发】【自定义排行控件的实现】【Actionbar的使用】

1.应用详情页-截图模块开发

1.1 效果及思路

【思路】可以左右滑动,但是不会根据滑动的位置自动的更改位置;

 使用水平的srollerView,然后将图片添加进去即可;

1.

1.2 截图的布局

【布局】直接使用HorizontalScrollView容器布局,直接填充图片即可;

1.3.初始化布局

【初始化布局】需要使用一个Holder初始化布局;

【布局文件】准备5个ImageView,虽然有的页面达不到5个,但是也应该准备好;

【源码】/GooglePlay74/res/layout/layout_detail_picinfo.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="wrap_content"
 5     android:paddingTop="3dp"
 6     android:paddingBottom="3dp"
 7     android:orientation="horizontal" >
 8 
 9     <ImageView
10         android:id="@+id/iv_pic1"
11         android:layout_width="90dp"
12         android:layout_height="150dp"
13         android:layout_marginLeft="3dp" />
14 
15     <ImageView
16         android:id="@+id/iv_pic2"
17         android:layout_width="90dp"
18         android:layout_height="150dp"
19         android:layout_marginLeft="3dp" />
20 
21     <ImageView
22         android:id="@+id/iv_pic3"
23         android:layout_width="90dp"
24         android:layout_height="150dp"
25         android:layout_marginLeft="3dp" />
26 
27     <ImageView
28         android:id="@+id/iv_pic4"
29         android:layout_width="90dp"
30         android:layout_height="150dp"
31         android:layout_marginLeft="3dp" />
32 
33     <ImageView
34         android:id="@+id/iv_pic5"
35         android:layout_width="90dp"
36         android:layout_height="150dp"
37         android:layout_marginLeft="3dp" />
38 
39 </LinearLayout>

 【注意】正确的写法是在initView中写;因为继承在父类中,首先会调用父类的构造方法,然后调用initView();写在外面会导致错误,编译挂掉;

 

【源码】/GooglePlay74/src/com/itheima/googleplay74/ui/holder/DetailPicsHolder.java

 1 package com.itheima.googleplay74.ui.holder;
 2 
 3 import java.util.ArrayList;
 4 
 5 import android.content.Intent;
 6 import android.view.View;
 7 import android.view.View.OnClickListener;
 8 import android.widget.ImageView;
 9 
10 import com.itheima.googleplay74.R;
11 import com.itheima.googleplay74.domain.AppInfo;
12 import com.itheima.googleplay74.http.HttpHelper;
13 import com.itheima.googleplay74.utils.BitmapHelper;
14 import com.itheima.googleplay74.utils.UIUtils;
15 import com.lidroid.xutils.BitmapUtils;
16 
17 /**
18  * 首页详情页-截图
19  * 
20  * @author Kevin
21  * @date 2015-11-3
22  */
23 public class DetailPicsHolder extends BaseHolder<AppInfo> {
24 
25     private ImageView[] ivPics;
26     private BitmapUtils mBitmapUtils;
27 
28     @Override
29     public View initView() {
30         View view = UIUtils.inflate(R.layout.layout_detail_picinfo);
31 
32         ivPics = new ImageView[5];
33         ivPics[0] = (ImageView) view.findViewById(R.id.iv_pic1);
34         ivPics[1] = (ImageView) view.findViewById(R.id.iv_pic2);
35         ivPics[2] = (ImageView) view.findViewById(R.id.iv_pic3);
36         ivPics[3] = (ImageView) view.findViewById(R.id.iv_pic4);
37         ivPics[4] = (ImageView) view.findViewById(R.id.iv_pic5);
38 
39         mBitmapUtils = BitmapHelper.getBitmapUtils();
40 
41         return view;
42     }
43 
44     @Override
45     public void refreshView(AppInfo data) {
46         final ArrayList<String> screen = data.screen;
47 
48         for (int i = 0; i < 5; i++) {
49             if (i < screen.size()) {
50                 mBitmapUtils.display(ivPics[i], HttpHelper.URL + "image?name="
51                         + screen.get(i));
52             } else {
53                 ivPics[i].setVisibility(View.GONE);
54             }
55         }
56 
57     }
58 
59 }

 【应用详情中调用此Holder】填充不同的应用详情的界面的数据;

 

【BUG】签名一致,先删除安装的应用程序;

 

 

【中间的图片的点击查看大图】

【思路】为图片增加点击事件的监听,然后跳转到另外一个Activity,在Activity中使用类似于首页新闻头条的滑动效果,但是需要在跳转的时候传递数据(要加载图片的集合screen和该位置的图片(i));

 此处没有实现;

2.应用详情页-描述模块开发

2.1 效果及思路

【思路】就是TextView的组合;

2.2【添加框架中的帧布局】

【初始化布局的数据】

2.3【Hodler的添加】

[描述的布局源码]

 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:orientation="vertical" >
 6 
 7     <TextView
 8         android:layout_width="wrap_content"
 9         android:layout_height="wrap_content"
10         android:text="应用介绍"
11         android:textColor="#9e9e9e"
12         android:textSize="16sp" />
13 
14     <TextView
15         android:id="@+id/tv_detail_des"
16         android:layout_width="match_parent"
17         android:layout_height="wrap_content"
18         android:textColor="#9e9e9e"
19         android:textSize="14sp" />
20 
21     <RelativeLayout
22         android:id="@+id/rl_detail_toggle"
23         android:layout_width="match_parent"
24         android:layout_height="wrap_content" >
25 
26         <TextView
27             android:id="@+id/tv_detail_author"
28             android:layout_width="wrap_content"
29             android:layout_height="wrap_content"
30             android:layout_centerVertical="true"
31             android:textColor="#000"
32             android:textSize="14sp" />
33 
34         <ImageView
35             android:id="@+id/iv_arrow"
36             android:layout_width="wrap_content"
37             android:layout_height="wrap_content"
38             android:layout_alignParentRight="true"
39             android:layout_centerVertical="true"
40             android:src="@drawable/arrow_down" />
41     </RelativeLayout>
42 
43 </LinearLayout>

 [现阶段的部分源码]

 1 package com.itheima.googleplay74.ui.holder;
 2 
 3 import android.util.TypedValue;
 4 import android.view.View;
 5 import android.view.View.MeasureSpec;
 6 import android.view.View.OnClickListener;
 7 import android.view.ViewParent;
 8 import android.widget.ImageView;
 9 import android.widget.LinearLayout;
10 import android.widget.RelativeLayout;
11 import android.widget.ScrollView;
12 import android.widget.TextView;
13 
14 import com.itheima.googleplay74.R;
15 import com.itheima.googleplay74.domain.AppInfo;
16 import com.itheima.googleplay74.utils.UIUtils;
17 import com.nineoldandroids.animation.Animator;
18 import com.nineoldandroids.animation.Animator.AnimatorListener;
19 import com.nineoldandroids.animation.ValueAnimator;
20 import com.nineoldandroids.animation.ValueAnimator.AnimatorUpdateListener;
21 
22 /**
23  * 详情页-应用描述
24  * 
25  * @author Kevin
26  * @date 2015-11-3
27  */
28 public class DetailDesHolder extends BaseHolder<AppInfo> {
29 
30     private TextView tvDes;
31     private TextView tvAuthor;
32     private ImageView ivArrow;
33     private RelativeLayout rlToggle;
34 
35     @Override
36     public View initView() {
37         View view = UIUtils.inflate(R.layout.layout_detail_desinfo);
38 
39         tvDes = (TextView) view.findViewById(R.id.tv_detail_des);
40         tvAuthor = (TextView) view.findViewById(R.id.tv_detail_author);
41         
42         return view;
43     }
44 
45     @Override
46     public void refreshView(AppInfo data) {
47         tvDes.setText(data.des);
48         tvAuthor.setText(data.author);
49 
50         });
51     }

 【初始化描述的模块的完善】设置数据;

【测试】无法滑动,因为现在是线性布局,应该添加scrllView布局进行包括,就可以滑动了;

2.4【布局中添加scrollView】

【测试2】并非要完成显示所有的文字内容,而是只展示7行的内容;通过点击箭头进行切换完整内容的显示;

【效果】并非要完成显示所有的文字内容,而是只展示7行的内容;通过点击箭头进行切换完整内容的显示

 

2.5 文件的部分显示

【思路】模拟七行的TextView的高度,然后将文字的高度进行测量然后设置。

【设置默认的TextView的高度】

【测试3】展示七行的效果

【增加文字的边距】

 

2.5 增加点击文本显示展开和收起的效果

【注意】要判断描述信息大于7行的时候才启动点击效果

【测试4】达到点击展开的效果,但是还需要点击之后文字自动全部显示;

 

2.6 点击之后文字自动全部显示

【思路】在接收点击事件之后scrollView自动展开内容;

【scrollView的查找】scrollView是在整个大布局中,而在详情描述并没有该scrollView;此控件的查找有两种思路;

【思路1】通过构造方法传递该参数;

【思路2】详情描述的控件的祖先必然存在scrollView,可以一级级的查找,本次使用该方法;

【查找scrollView的源码】

【滚动动作】在动画结束之后进行滚动;

 【增加箭头的切换】

【BUG】本身文字的高度不到7行,现在显示的还是7行,产生了空白;

[原因]系统也是需要事件缓冲的,直接运行无法直接响应;

[测试效果]展示3行了;

=====自定义排行控件=======

3.自定义排行控件原理分析

 

【分析】会出现的几种情况

4.自定义排行控件的onMeasure测量

【获取有效宽高/测量子控件的宽度】

 

4.1 第一种情况:增加子控件超边界需要换行 

【对已经占据的宽度记录判断】

【水平控件之间的间距】

【超出边界与否的判断】

【换行对象】

【为当前行增加子控件】

【换行类生成】

【增加换行功能】第一个情况解决;

4.2 超出边界的考虑

【超出边界的考虑】

 

【获取孩子的数量】

【超出边界的分类】

【第三种情况的处理】控件很长,强制添加,然后换行;属于else的情况1;

【第二种情况的处理】先换行,再添加,宽度累计增加;

【将最后一行的数据添加后集合中】在newLine中保存的是上一行的数据,在for循环结束之后,最后一行的控件可能无法添加;

【根据尺寸重新绘制】

【onMeasure方法源码】

  1 package com.itheima.googleplay74.ui.view;
  2 
  3 import java.util.ArrayList;
  4 
  5 import com.itheima.googleplay74.utils.UIUtils;
  6 
  7 import android.content.Context;
  8 import android.util.AttributeSet;
  9 import android.view.View;
 10 import android.view.ViewGroup;
 11 
 12 public class MyFlowLayout extends ViewGroup {
 13 
 14     private int mUsedWidth;// 当前行已使用的宽度
 15     private int mHorizontalSpacing = UIUtils.dip2px(6);// 水平间距
 16     private int mVerticalSpacing = UIUtils.dip2px(8);// 竖直间距
 17 
 18     private Line mLine;// 当前行对象
 19 
 20     private ArrayList<Line> mLineList = new ArrayList<MyFlowLayout.Line>();// 维护所有行的集合
 21 
 22     private static final int MAX_LINE = 100;// 最大行数是100行
 23 
 24     public MyFlowLayout(Context context, AttributeSet attrs, int defStyle) {
 25         super(context, attrs, defStyle);
 26     }
 27 
 28     public MyFlowLayout(Context context, AttributeSet attrs) {
 29         super(context, attrs);
 30     }
 31 
 32     public MyFlowLayout(Context context) {
 33         super(context);
 34     }

50 @Override 51 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 52 // 获取有效宽度 53 int width = MeasureSpec.getSize(widthMeasureSpec) - getPaddingLeft() 54 - getPaddingRight(); 55 // 获取有效高度 56 int height = MeasureSpec.getSize(heightMeasureSpec) - getPaddingTop() 57 - getPaddingBottom(); 58 59 // 获取宽高模式 60 int widthMode = MeasureSpec.getMode(widthMeasureSpec); 61 int heightMode = MeasureSpec.getMode(heightMeasureSpec); 62 63 int childCount = getChildCount();// 获取所有子控件数量 64 for (int i = 0; i < childCount; i++) { 65 View childView = getChildAt(i); 66 67 // 如果父控件是确定模式, 子控件包裹内容;否则子控件模式和父控件一致 68 int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(width, 69 (widthMode == MeasureSpec.EXACTLY) ? MeasureSpec.AT_MOST 70 : widthMode); 71 int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height, 72 (heightMode == MeasureSpec.EXACTLY) ? MeasureSpec.AT_MOST 73 : heightMode); 74 75 // 开始测量 76 childView.measure(childWidthMeasureSpec, childHeightMeasureSpec); 77 78 // 如果当前行对象为空, 初始化一个行对象 79 if (mLine == null) { 80 mLine = new Line(); 81 } 82 83 // 获取子控件宽度 84 int childWidth = childView.getMeasuredWidth(); 85 86 mUsedWidth += childWidth;// 已使用宽度增加一个子控件宽度 87 88 if (mUsedWidth < width) {// 判断是否超出了边界 89 mLine.addView(childView);// 更当前行对象添加子控件 90 91 mUsedWidth += mHorizontalSpacing;// 增加一个水平间距 92 93 if (mUsedWidth > width) { 94 // 增加水平间距之后, 就超出了边界, 此时需要换行 95 if (!newLine()) { 96 break;// 如果创建行失败,就结束循环,不再添加 97 } 98 } 99 100 } else { 101 // 已超出边界 102 // 1.当前没有任何控件, 一旦添加当前子控件, 就超出边界(子控件很长) 103 if (mLine.getChildCount() == 0) { 104 mLine.addView(childView);// 强制添加到当前行 105 106 if (!newLine()) {// 换行 107 break; 108 } 109 } else { 110 // 2.当前有控件, 一旦添加, 超出边界 111 if (!newLine()) {// 换行 112 break; 113 } 114 115 mLine.addView(childView); 116 mUsedWidth += childWidth + mHorizontalSpacing;// 更新已使用宽度 117 } 118 } 119 120 } 121 122 // 保存最后一行的行对象 123 if (mLine != null && mLine.getChildCount() != 0 124 && !mLineList.contains(mLine)) { 125 mLineList.add(mLine); 126 } 127 128 int totalWidth = MeasureSpec.getSize(widthMeasureSpec);// 控件整体宽度 129 130 int totalHeight = 0;// 控件整体高度 131 for (int i = 0; i < mLineList.size(); i++) { 132 Line line = mLineList.get(i); 133 totalHeight += line.mMaxHeight; 134 } 135 136 totalHeight += (mLineList.size() - 1) * mVerticalSpacing;// 增加竖直间距 137 totalHeight += getPaddingTop() + getPaddingBottom();// 增加上下边距 138 139 // 根据最新的宽高来测量整体布局的大小 140 setMeasuredDimension(totalWidth, totalHeight); 141 // super.onMeasure(widthMeasureSpec, heightMeasureSpec); 142 } 143 144 // 换行 145 private boolean newLine() { 146 mLineList.add(mLine);// 保存上一行数据 147 148 if (mLineList.size() < MAX_LINE) { 149 // 可以继续添加 150 mLine = new Line(); 151 mUsedWidth = 0;// 已使用宽度清零 152 153 return true;// 创建行成功 154 } 155 156 return false;// 创建行失败 157 } 158 159 // 每一行的对象封装 160 class Line { 161 162 private int mTotalWidth;// 当前所有控件总宽度 163 public int mMaxHeight;// 当前控件的高度(以最高的控件为准) 164 165 private ArrayList<View> mChildViewList = new ArrayList<View>();// 当前行所有子控件集合 166 167 // 添加一个子控件 168 public void addView(View view) { 169 mChildViewList.add(view); 170 // 总宽度增加 171 mTotalWidth += view.getMeasuredWidth(); 172 173 int height = view.getMeasuredHeight(); 174 // 0 10 20 10 175 mMaxHeight = mMaxHeight < height ? height : mMaxHeight; 176 } 177 178 public int getChildCount() { 179 return mChildViewList.size(); 180 }

 5.自定义排行控件的onLayout布局

【思路】每一行的对象控制好各自各行的小控件,然后在Activity中控制好每一行;

5.1 每行的子控件的位置的布局

【说明】需要知道每个子控件的左上角的坐标(left,top),然后子控件知道自己的宽高,就可以画出来了;

【存在剩余空间的情况】【需要考虑的特殊情况】最后黄色布局剩余了空间;

【修改】需要改为确定的值;

 

【控件高度不一致的情况的画法】

【考虑第二个控件的横向尺寸值】增加前一个控件的横向尺寸值和一个横向的边距值;

【出现负值的情况】

5.2 大布局中的每行的排列

 【修改使用到项目中】

【测试】效果与之前的一致;

 6.Actionbar的使用

 

6.1 对应的加载布局

6.2 属性值的含义

【orderInCategory】当前的item属于的级别,可能存在多个item,各有级别;

【showAsaction】展现的方式

[always]一直展现出来;

[never]永远都是隐藏,需要点击才会显示出来;

 

[ifroom]如果空间容许的话就展现;

6.3 展示图片

 

【长按可以弹出土司】可以通过长按点击可以判断是否为ActionBar开发的;微信的搜索按钮可以长按弹吐司;

【ActionBar的点击事件处理】

 

【修改标题】

【设置图标】

【设置图标是否可以被点击】true:可以被点击;false:不可以被点击;

 【隐藏图标】

 【显示返回键】

【返回按键的事件响应】

7.使用Actionbar改造电子市场&侧边栏效果DrawerLayout

7.1 效果及思路

【思路】点击按钮之后会出现侧边栏,侧边栏使用的是另外一种方式,谷歌原生的效果,DrawerLayout;

 

7.2 侧边栏的构造

【说明】使用下面的谷歌提供的DrawerLayout侧边栏效果的控件;

【谷歌提供的DrawerLayout侧边栏效果的控件】类似于帧布局,将侧边栏和内容页重叠在了一起;

 

【初始化抽屉数据】

【该方法调用的时机】

【拦截点击图标的事件】

【在详情页面添加返回键】

7.3 点评ActionBar

 【开源中国中使用的比较多】

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 2.

posted @ 2018-03-15 20:22  OzTaking  阅读(219)  评论(0)    收藏  举报