Day03
##3.1 前两天课程总结 ##
结合UI框架结构来分析
##3.2 细节处理 ##
-
页签右侧增加箭头
使用水平LinearLayout //点击事件处理 @OnClick(R.id.iv_news_tab_next) public void nextTab(View view) { mViewPager.setCurrentItem(mViewPager.getCurrentItem() + 1); }
-
页签滑动的事件处理
向右滑动页签条, 会把侧边栏拉出来, 为了避免这个问题, 可以 重写TabPageIndicator的方法: @Override public boolean dispatchTouchEvent(MotionEvent ev) { getParent().requestDisallowInterceptTouchEvent(true);//禁止父控件拦截触摸事件 return super.dispatchTouchEvent(ev); }
-
页签对应页面右划时,控制侧边栏显示和隐藏
mIndicator.setOnPageChangeListener(this);//设置ViewPager的滑动监听 @Override public void onPageSelected(int arg0) { Log.d(TAG, "onPageSelected=" + arg0); MainActivity mainUI = (MainActivity) mActivity; SlidingMenu slidingMenu = mainUI.getSlidingMenu(); if (arg0 == 0) { slidingMenu.setTouchModeAbove(SlidingMenu.TOUCHMODE_FULLSCREEN); } else { slidingMenu.setTouchModeAbove(SlidingMenu.TOUCHMODE_NONE); } } 注意: 如果ViewPagerIndicator和ViewPager搭配使用时, 设置ViewPager滑动监听的方法必须在ViewPagerIndicator中执行!!!!
##3.3 页签详情页开发 ##
-
布局文件
ViewPager + ListView
-
获取网络数据
-
对象封装
/** * 页签数据封装 * * @author Kevin * */ public class TabDetailBean { public int retcode; public TabDatailData data; public class TabDatailData { public String countcommenturl; public String more; public ArrayList<News> news; public String title; public ArrayList<Topic> topic; public ArrayList<TopNews> topnews; @Override public String toString() { return "TabDatailData [news=" + news + ", title=" + title + ", topnews=" + topnews + "]"; } } /** * 新闻列表 * * @author Kevin * */ public class News { public String comment; public String commentlist; public String commenturl; public String id; public String listimage; public String pubdate; public String title; public String type; public String url; @Override public String toString() { return "News [title=" + title + "]"; } } public class Topic { public String description; public String id; public String listimage; public String sort; public String title; public String url; } /** * 顶部新闻条 * * @author Kevin * */ public class TopNews { public String comment; public String commentlist; public String commenturl; public String id; public String topimage; public String pubdate; public String title; public String type; public String url; @Override public String toString() { return "TopNews [topimage=" + topimage + ", title=" + title + "]"; } } @Override public String toString() { return "TabDetailBean [data=" + data + "]"; } }
-
缓存处理
-
数据展示
-
顶部新闻数据展示(轮播条)
-
ViewPager适配器
@Override public Object instantiateItem(ViewGroup container, int position) { ImageView image = new ImageView(mActivity); image.setScaleType(ScaleType.FIT_XY);//设置图片展现样式为: 宽高填充ImageView(图片可能被拉伸或者缩放) image.setImageResource(R.drawable.topnews_item_default); container.addView(image); utils.display(image, mTopNews.get(position).topimage);//参1表示ImageView对象, 参2表示图片url return image; }
-
ScaleType简单介绍
<ImageView android:layout_width="100dp" android:layout_height="100dp" android:scaleType="centerCrop" android:src="@drawable/image_demo" />
-
处理轮播条滑动事件(自定义HorizontalScrollViewPager)
@Override public boolean dispatchTouchEvent(MotionEvent ev) { // 请求父控件不要拦截触摸事件 getParent().requestDisallowInterceptTouchEvent(true); return super.dispatchTouchEvent(ev); }
-
使用BitmapUtils加载网络图片
BitmapUtils utils = new BitmapUtils(mActivity); utils.configDefaultLoadingImage(R.drawable.topnews_item_default);// 设置加载中的图片 utils.display(image, mTopNews.get(position).topimage);//参1表示ImageView对象, 参2表示图片url
-
添加轮播条位置指示器
查看Demo中的SampleCirclesSnap.java, 仿照该方法添加代码 CirclePageIndicator mIndicator; mIndicator.setViewPager(mViewPager); mIndicator.setSnap(true);// 设置圆点的切换方式, 快照方式
-
位置指示器样式修改
<com.viewpagerindicator.CirclePageIndicator android:id="@+id/cpi_tab_detail" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_centerVertical="true" android:background="@android:color/transparent"//背景色 android:padding="5dp" app:fillColor="#ff0000"//选中后的颜色 app:pageColor="#aaaaaa"//默认颜色 app:radius="3dp"//半径 app:strokeWidth="0dp" //圆环线条的粗细 />
-
头条新闻标题TextView赋值
-
头条新闻滑动事件细节优化
/** * 上下滑动时, 父控件拦截事件 * * 向右滑动, 当前页是第一页时, 父控件拦截事件; 向左滑动, 当前是最后一页时, 父控件拦截事件 */ @Override public boolean dispatchTouchEvent(MotionEvent ev) { switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: // 请求父控件不要拦截触摸事件 getParent().requestDisallowInterceptTouchEvent(true); startX = ev.getX(); startY = ev.getY(); break; case MotionEvent.ACTION_MOVE: float endX = ev.getX(); float endY = ev.getY(); float dx = endX - startX; float dy = endY - startY; // 判断是会否左右滑动 if (Math.abs(dx) > Math.abs(dy)) { // 向右滑动 if (dx > 0) { if (getCurrentItem() == 0) { getParent().requestDisallowInterceptTouchEvent(false); } } else { if (getCurrentItem() == getAdapter().getCount() - 1) { getParent().requestDisallowInterceptTouchEvent(false); } } } else { getParent().requestDisallowInterceptTouchEvent(false); } break; default: break; } return super.dispatchTouchEvent(ev); }
-
注意
多切换几个页签后, ViewPager会重新初始化页面,显示第一张图片, 但是CirclePageIndicator默认会保存上次滑动位置, 导致小圆点显示的位置不准确.可以在初始化Indicator时, 增加下面代码: mIndicator.onPageSelected(0);//设置当前选中页面为第一个, 保证圆点标记位置正确
-
-
列表新闻展示
-
ListView元素布局
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="10dp" > <ImageView android:id="@+id/iv_news_icon" android:layout_width="100dp" android:layout_height="60dp" android:layout_alignParentLeft="true" android:layout_alignParentTop="true" android:layout_centerVertical="true" android:layout_marginRight="5dp" android:background="#999999" android:padding="1dp" android:scaleType="fitXY" android:src="@drawable/image_demo" /> <TextView android:id="@+id/tv_news_title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:layout_marginBottom="5dp" android:layout_toRightOf="@+id/iv_news_icon" android:ellipsize="end" android:lines="2" android:text="饭卡上剪短发了卡死的减肥路口见阿斯顿浪费就爱谁离开发顺丰卡死的卷发山东龙口锋娟啊的" android:textColor="#000000" android:textSize="18sp" /> <TextView android:id="@+id/tv_news_time" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignLeft="@+id/tv_news_title" android:layout_below="@id/tv_news_title" android:text="2015-01-09 16:32" android:textColor="#999999" android:textSize="15sp" /> </RelativeLayout>
-
ListView滑动出现黑色背景的问题
android:cacheColorHint="#fff"//设置改属性,颜色值为白色
-
ListView增加HeaderView, 使顶部新闻和列表新闻成为一个整体
View headerView = View.inflate(mActivity, R.layout.top_news_header_view, null); lvList.addHeaderView(headerView);// 增加顶部新闻为HeaderView
-
使用ViewHolder对ListView进行优化
-
ListView网络数据填充
-
-
-
自定义下拉刷新
-
自定义ListView
-
ListView头布局
refresh_listview_header.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" > <FrameLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingBottom="10dp" android:paddingLeft="10dp" android:paddingTop="10dp" android:layout_gravity="center" > <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:src="@drawable/common_listview_headview_red_arrow" /> <ProgressBar android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:indeterminateDrawable="@drawable/custom_progressbar" android:visibility="invisible" /> </FrameLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:gravity="center" android:orientation="vertical" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="下拉刷新" android:textSize="16sp" android:textColor="#ff0000" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="5dp" android:text="最后刷新时间: 1990-09-09 09:09:09" /> </LinearLayout> </LinearLayout>
-
自定义ProgressBar
<?xml version="1.0" encoding="utf-8"?> <rotate xmlns:android="http://schemas.android.com/apk/res/android" android:fromDegrees="0" android:pivotX="50%" android:pivotY="50%" android:toDegrees="360" > <shape android:innerRadius="15dp" android:shape="ring" android:thickness="3dp" android:useLevel="false" > <gradient android:centerColor="#33ff0000" android:endColor="#ffffff" android:startColor="#ff0000" android:type="sweep" /> </shape> </rotate>
-
初始化头布局
/** * 初始化头布局 */ private void initHeaderView() { mHeaderView = View.inflate(getContext(), R.layout.refresh_listview_header, null); ivArrow = (ImageView) mHeaderView .findViewById(R.id.iv_pull_list_header); pbProgress = (ProgressBar) mHeaderView .findViewById(R.id.pb_pull_list_header); tvTitle = (TextView) mHeaderView .findViewById(R.id.tv_pull_list_header_title); tvTime = (TextView) mHeaderView .findViewById(R.id.tv_pull_list_header_time); this.addHeaderView(mHeaderView); mHeaderView.measure(0, 0);// 测量View mHeaderHeight = mHeaderView.getMeasuredHeight();// 获取View的高度 LogUtils.d("header height=" + mHeaderHeight); mHeaderView.setPadding(0, -mHeaderHeight, 0, 0);// 隐藏头布局 initAnimation(); }
-
滑动事件处理
@Override public boolean onTouchEvent(MotionEvent ev) { switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: startY = (int) ev.getY(); break; case MotionEvent.ACTION_MOVE: if (startY == -1) { startY = (int) ev.getY(); } // 如果当前正在刷新, 不做任何处理 if (mCurrentState == REFRESHING) { break; } int endY = (int) ev.getY(); int dY = endY - startY;// 移动偏移量 int firstVisiblePosition = getFirstVisiblePosition();// 查看第一个显示的item属于第几个 LogUtils.d("firstVisiblePosition=" + firstVisiblePosition); if (dY > 0 && firstVisiblePosition == 0) {// 向下移动 int paddingTop = dY - mHeaderHeight; if (paddingTop > 0 && mCurrentState != RELEASE_REFRESH) {// 进入松开刷新的状态 mCurrentState = RELEASE_REFRESH; refreshHeaderViewState(); } else if (paddingTop < 0 && mCurrentState != PULL_DOWN_REFRESH) {// 进入下拉刷新状态 mCurrentState = PULL_DOWN_REFRESH; refreshHeaderViewState(); } mHeaderView.setPadding(0, paddingTop, 0, 0);// 设置头布局padding return true; } break; case MotionEvent.ACTION_UP: startY = -1; if (mCurrentState == RELEASE_REFRESH) { // 将当前状态更新为正在刷新 mCurrentState = REFRESHING; mHeaderView.setPadding(0, 0, 0, 0); refreshHeaderViewState(); } else if (mCurrentState == PULL_DOWN_REFRESH) { mHeaderView.setPadding(0, -mHeaderHeight, 0, 0);// 隐藏头布局 } break; default: break; } return super.onTouchEvent(ev); }
-
下拉刷新的几种状态
public static final int PULL_DOWN_REFRESH = 1;// 下拉刷新 public static final int RELEASE_REFRESH = 2;// 松开刷新 public static final int REFRESHING = 3;// 正在刷新 /** * 根据当前状态, 更新下拉刷新界面 */ private void refreshHeaderViewState() { switch (mCurrentState) { case PULL_DOWN_REFRESH: tvTitle.setText("下拉刷新"); ivArrow.setVisibility(View.VISIBLE); pbProgress.setVisibility(View.INVISIBLE); ivArrow.startAnimation(animDown); break; case RELEASE_REFRESH: tvTitle.setText("松开刷新"); ivArrow.setVisibility(View.VISIBLE); pbProgress.setVisibility(View.INVISIBLE); ivArrow.startAnimation(animUp); break; case REFRESHING: ivArrow.clearAnimation();// 必须清除动画, 否则View.INVISIBLE不起作用 tvTitle.setText("正在刷新..."); ivArrow.setVisibility(View.INVISIBLE); pbProgress.setVisibility(View.VISIBLE); if (mListener != null) { mListener.onRefresh();// 下拉刷新回调 } break; default: break; } }
-
下拉刷新箭头旋转动画
/** * 初始化箭头的旋转动画 */ private void initAnimation() { animUp = new RotateAnimation(0, -180, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); animUp.setDuration(200); animUp.setFillAfter(true); animDown = new RotateAnimation(-180, 0, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); animDown.setDuration(200); animDown.setFillAfter(true); }
-
下拉刷新监听
/** * 下拉刷新的回调接口 * @author Kevin * */ public interface RefreshListener { public void onRefresh(); } /** * 设置下拉刷新监听 * * @param listener */ public void setOnRefreshListener(RefreshListener listener) { mListener = listener; }
-
增加下拉刷新时间
/** * 获取格式化后的当前时间 */ public String getCurrentTime() { SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); return format.format(new Date()); }
-
收起下拉刷新控件
/** * 当刷新完成后,隐藏下拉刷新控件, 初始化各项数据 */ public void onRefreshComplete(boolean needUpdateTime) { mHeaderView.setPadding(0, -mHeaderHeight, 0, 0); tvTitle.setText("下拉刷新"); ivArrow.setVisibility(View.VISIBLE); pbProgress.setVisibility(View.INVISIBLE); if (needUpdateTime) { tvTime.setText(getCurrentTime()); } mCurrentState = PULL_DOWN_REFRESH; }
-
第一次初始化数据时, 显示下拉刷新控件
/** * 第一次初始化数据时, 显示下拉刷新控件 */ public void setRefreshing() { tvTitle.setText("正在刷新..."); ivArrow.setVisibility(View.INVISIBLE); pbProgress.setVisibility(View.VISIBLE); mHeaderView.setPadding(0, 0, 0, 0); }
-
##3.4 第三天总结 ##