UI框架图
1.监听动画结束
set.setAnimationListener(new AnimationListener() {
@Override
public void onAnimationEnd(Animation arg0) {
JumpActivity();
}
@Override
public void onAnimationRepeat(Animation arg0) {
// TODO Auto-generated method stub
}
@Override
public void onAnimationStart(Animation arg0) {
// TODO Auto-generated method stub
}</span></span>
2.SharePreferece封装
/**
* 专门访问和设置SharePreference的工具类, 保存和配置一些设置信息
*
* @author Kevin
*
*/
public class SharePreferenceUtils {
private static final String SHARE_PREFS_NAME = "itheima";
private static SharedPreferences mSharedPreferences;
public static void putBoolean(Context ctx, String key, boolean value) {
if (mSharedPreferences == null) {
mSharedPreferences = ctx.getSharedPreferences(SHARE_PREFS_NAME,
Context.MODE_PRIVATE);
}
mSharedPreferences.edit().putBoolean(key, value).commit();
}
public static boolean getBoolean(Context ctx, String key,
boolean defaultValue) {
if (mSharedPreferences == null) {
mSharedPreferences = ctx.getSharedPreferences(SHARE_PREFS_NAME,
Context.MODE_PRIVATE);
}
return mSharedPreferences.getBoolean(key, defaultValue);
}
public static void putString(Context ctx, String key, String value) {
if (mSharedPreferences == null) {
mSharedPreferences = ctx.getSharedPreferences(SHARE_PREFS_NAME,
Context.MODE_PRIVATE);
}
mSharedPreferences.edit().putString(key, value).commit();
}
public static String getString(Context ctx, String key, String defaultValue) {
if (mSharedPreferences == null) {
mSharedPreferences = ctx.getSharedPreferences(SHARE_PREFS_NAME,
Context.MODE_PRIVATE);
}
return mSharedPreferences.getString(key, defaultValue);
}
}
3.static作用详解
(1)被static修饰的成员变量和成员方法独立于该类的任何对象。也就是说,它不依赖类特定的实例,被类的所有实例共享
(2)只要这个类被加载,Java虚拟机就能根据类名在运行时数据区的方法区内定找到他们。因此,static对象可以在它的任何对象创 建之前访问,无需引用任何对象。
boolean userGuide = PrefUtils.getBoolean(this, "is_user_guide_showed",
false);
//无需实例PrefUtils对象,直接用
方法必须是static
public static boolean getBoolean(Context ctx, String key,
boolean defaultValue) {
SharedPreferences sp = ctx.getSharedPreferences(PREF_NAME,
Context.MODE_PRIVATE);
return sp.getBoolean(key, defaultValue);
}
4.引导页
<android.support.v4.view.ViewPager
android:id="@+id/vp_guide"
android:layout_width="match_parent"
android:layout_height="match_parent" />
/**
* ViewPager数据适配器
*
* @author Kevin
*
*/
class GuideAdapter extends PagerAdapter {
@Override
public int getCount() {
return mImageIds.length;
}
@Override
public boolean isViewFromObject(View arg0, Object arg1) {
return arg0 == arg1;
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
container.addView(mImageViewList.get(position));
return mImageViewList.get(position);
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
}
(3)图片资源&使用
private static final int[] mImageIds = new int[] { R.drawable.guide_1,
R.drawable.guide_2, R.drawable.guide_3 };
image.setBackgroundResource(mImageIds[i]);// 设置引导页背景
(4)在ViewPager上添加ImageView,初始化界面时创建对应个ImageView
mImageViewList = new ArrayList<ImageView>();
//private ArrayList<ImageView> mImageViewList;
// 初始化引导页的3个页面
for (int i = 0; i < mImageIds.length; i++) {
ImageView image = new ImageView(this);
image.setBackgroundResource(mImageIds[i]);// 设置引导页背景
mImageViewList.add(image);
}
(5)引导小点&开始体验按钮----------(自己画)
<?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="match_parent" >
<android.support.v4.view.ViewPager
android:id="@+id/vp_guide"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<Button
android:id="@+id/btn_start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="60dp"
android:background="@drawable/btn_guide_selector"
android:padding="5dp"
android:text="开始体验"
android:visibility="invisible"
android:textColor="@drawable/btn_guide_text_selector" />
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="20dp" >
<LinearLayout
android:id="@+id/ll_point_group"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal" >
</LinearLayout>
<View
android:id="@+id/view_red_point"
android:layout_width="10dp"
android:layout_height="10dp"
android:background="@drawable/shape_point_red" />
</RelativeLayout>
</RelativeLayout>
b.开始体验Button两个状态选择器(新建一个drawable文件夹)
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/button_red_pressed" android:state_pressed="true"/>
<item android:drawable="@drawable/button_red_normal"/>
</selector>
文字状态选择器
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" android:color="@android:color/black"/>
<item android:color="@android:color/white"/>
</selector>
c.小点,在代码中动态添加, 布局如下
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="20dp" >
<LinearLayout
android:id="@+id/ll_point_group"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal" >
</LinearLayout>
<View
android:id="@+id/view_red_point"
android:layout_width="10dp"
android:layout_height="10dp"
android:background="@drawable/shape_point_red" />
</RelativeLayout>
向LinearLayout中添加白色小点,View为红色小点,方便移动
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval" >
<solid android:color="#f00" />
</shape>
d.动态添加白色小圆点(也是创建一个View,然后添加圆形背景)
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval" >
<solid android:color="@android:color/darker_gray" />
</shape>
****dp与px的转换
public class DensityUtils {
/**
* dp转px
*
* @param ctx
* @param dp
* @return
*/
public static int dp2px(Context ctx, float dp) {
float density = ctx.getResources().getDisplayMetrics().density;
int px = (int) (dp * density + 0.5f);
return px;
}
/**
* px转dp
*
* @param ctx
* @param px
* @return
*/
public static float px2dp(Context ctx, int px) {
float density = ctx.getResources().getDisplayMetrics().density;
float dp = px / density;
return dp;
}
}
****小白点
mImageList = new ArrayList<ImageView>();
for (int i = 0; i < imageResIDs.length; i++) {
ImageView image = new ImageView(this);
image.setBackgroundResource(imageResIDs[i]);// 注意设置背景, 才可以填充屏幕
mImageList.add(image);
View point = new View(this);
point.setBackgroundResource(R.drawable.shape_guide_point_default);
LayoutParams params = new LayoutParams(
DensityUtils.dp2px(this, 10), DensityUtils.dp2px(this, 10));
if (i != 0) {
params.leftMargin = DensityUtils.dp2px(this, 10);
}
point.setLayoutParams(params);
llPointGroup.addView(point);
}
}
*****小红点移动(获取白点之间的距离,通过ViewPager的滑动监听,使view移动)
// measure -> layout -> draw
// 获得视图树观察者, 观察当整个布局的layout时的事件
viewRedPoint.getViewTreeObserver().addOnGlobalLayoutListener(
new OnGlobalLayoutListener() {
// 完成布局后会回调改方法, 改方法可能会被回调多次
@Override
public void onGlobalLayout() {
// 此方法只需要执行一次就可以: 把当前的监听事件从视图树中移除掉, 以后就不会在回调此事件了.
viewRedPoint.getViewTreeObserver()
.removeGlobalOnLayoutListener(this);
mPointWidth = llPointGroup.getChildAt(1).getLeft()
- llPointGroup.getChildAt(0).getLeft();
System.out.println("间距: " + mPointWidth);
}
});
监听ViewPager的滑动,使小红点移动
mViewPager.setOnPageChangeListener(new OnPageChangeListener() {
// 页面选中
@Override
public void onPageSelected(int position) {
// Log.d(TAG, "onPageSelected:" + position);
if (position == mImageList.size() - 1) {
btnStart.setVisibility(View.VISIBLE);
} else {
btnStart.setVisibility(View.GONE);
}
}
/**
* 页面滑动监听
*
* @params position 当前选中的位置
* @params positionOffset 偏移百分比
* @params positionOffsetPixels 页面偏移长度
*/
@Override
public void onPageScrolled(int position, float positionOffset,
int positionOffsetPixels) {
int leftMargin = (int) (mPointWidth * (positionOffset + position));
// Log.d(TAG, "当前位置:" + position + ";偏移比例:" + positionOffset
// + ";点偏移:" + leftMargin);
RelativeLayout.LayoutParams lp = (android.widget.RelativeLayout.LayoutParams) viewRedPoint
.getLayoutParams();
lp.leftMargin = leftMargin;
viewRedPoint.setLayoutParams(lp);
}
// 状态改变
@Override
public void onPageScrollStateChanged(int state) {
// Log.d(TAG, "onPageScrollStateChanged:" + state);
}
});
}
5.SlidingMenu的使用
public class MainActivity extends SlidingFragmentActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);// 去除标题
setContentView(R.layout.activity_main);// 配置主界面
// 配置左侧菜单
setBehindContentView(R.layout.left_menu);
// 设置菜单模式
SlidingMenu slidingMenu = getSlidingMenu();
slidingMenu.setMode(SlidingMenu.LEFT);
// 设置触摸模式
slidingMenu.setTouchModeAbove(SlidingMenu.TOUCHMODE_FULLSCREEN);
// 设置主界面显示宽度
int width = getWindowManager().getDefaultDisplay().getWidth();
slidingMenu.setBehindOffset(width*3/5);
}
(4)用Fragment去填充一个空布局(FramLayout),两边布局写成FramLayout,动态添加Fragment
private static final String FRAG_CONTENT = "frag_content";// 主页面Fragment的标记
private static final String FRAG_MENU_LEFT = "frag_menu_left";// 侧边栏Fragment的标记
/**
* 初始化Fragment
*/
private void initFragment() {
FragmentManager fm = getSupportFragmentManager();
// 开启事务
FragmentTransaction ft = fm.beginTransaction();
// 替换帧布局
ft.replace(R.id.fl_left_menu, new LeftMenuFragment(), FRAG_MENU_LEFT);
ft.replace(R.id.fl_main, new ContentFragment(), FRAG_CONTENT);
// 提交事务
ft.commit();
// fm.findFragmentByTag(arg0); 根据tag获取Fragment对象
}
(5)把Fragment共性抽取成基类
/**
* 基类Fragment, 所有Fragment继承此类
*
* 1. 定义Activity常量,方便子类使用 2. 定义抽象方法initViews,初始化布局,必须实现 3.
* 定义方法initData,初始化数据,可以不实现
*
* @author Kevin
*
*/
public abstract class BaseFragment extends Fragment {
public Activity mActivity;
// Fragment创建
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mActivity = getActivity();
}
// Fragment填充布局
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = initView();
return view;
}
/**
* 初始化布局
*
* @return
*/
public abstract View initView();
// Fragment所依赖的Activity创建完成
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
initData();
}
/**
* 初始化数据
*/
public void initData() {
}
}
***abstract
abstract修饰类,会使这个类成为一个抽象类,这个类将不能生成对象实例
abstract修饰方法,会使这个方法变成抽象方法,也就是只有声明(定义)而没有实现,实现部分以";"代替。需要子类继承实现(覆盖)
(6)主页面(ContentFragment)分析:实际上为一个ViewPager和RadioButton
*a.RadioButton
*b.RadioButton的样式
<style name="bottom_tab_style">
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_weight">1</item>
<item name="android:background">@android:color/transparent</item>
<item name="android:button">@android:color/transparent</item>
<item name="android:gravity">center</item>
<item name="android:drawablePadding">5dip</item>
<item name="android:textColor">@drawable/txt_bottom_tab_selector</item>
<item name="android:textSize">14sp</item>
</style>
*c
<RadioGroup
android:id="@+id/rg_content_group"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="@drawable/bottom_tab_bg"
android:gravity="center"
android:orientation="horizontal" >
<RadioButton
android:id="@+id/rb1"
style="@style/bottom_tab_style"
android:drawableTop="@drawable/btn_bottom_home_selector"
android:text="首页" />
<RadioButton
android:id="@+id/rb1"
style="@style/bottom_tab_style"
android:drawableTop="@drawable/btn_bottom_news_selector"
android:text="新闻中心" />
<RadioButton
android:id="@+id/rb1"
style="@style/bottom_tab_style"
android:drawableTop="@drawable/btn_bottom_service_selector"
android:text="智慧服务" />
<RadioButton
android:id="@+id/rb1"
style="@style/bottom_tab_style"
android:drawableTop="@drawable/btn_bottom_gov_selector"
android:text="政务" />
<RadioButton
android:id="@+id/rb1"
style="@style/bottom_tab_style"
android:drawableTop="@drawable/btn_bottom_setting_selector"
android:text="设置" />
</RadioGroup>
mRadioGroup.check(R.id.rb_home);// 设置默认选项为首页
d.获取Fragment所依附的Activity
mActivity = getActivity();
e.把ViewPager中五个Pager抽取共性,变化的地方用FramLayout代替
*********Pager加载数据由外界调用,因为ViewPager会预加载下一页的,浪费资源
*********后期通过监听ViewPager哪个页面被选中,从而加载数据
<span style="font-size:14px;">/**
* 主页的各个子页面的父类
*
* @author Kevin
*
*/
public class BasePager {
public static final String TAG = BasePager.class.getSimpleName();
public Activity mActivity;
public TextView tvTitle;// 标题
public ImageButton btnMenu;// 菜单按钮
public FrameLayout flContent;// 正文
public View mRootView; // 根布局的view对象
public BasePager(Activity activity) {
mActivity = activity;
mRootView = initView();
}
/**
* 初始化View
*/
public View initView() {
View view = View.inflate(mActivity, R.layout.base_pager, null);
tvTitle = (TextView) view.findViewById(R.id.tv_title);
btnMenu = (ImageButton) view.findViewById(R.id.btn_menu);
flContent = (FrameLayout) view.findViewById(R.id.fl_content);
//点击按键, 打开/关闭侧边栏
btnMenu.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
MainActivity mainUI = (MainActivity) mActivity;
SlidingMenu slidingMenu = mainUI.getSlidingMenu();
slidingMenu.toggle();// 如果侧边栏打开,则关闭;如果关闭,则打开
}
});
return view;
}
/**
* 初始化数据
*/
public void initData() {
}
}</span>
布局:
<span style="font-size:14px;"><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/title_red_bg" >
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text=""
android:textColor="#fff"
android:textSize="23sp" />
<ImageButton
android:id="@+id/btn_menu"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="10dp"
android:background="@android:color/transparent"
android:src="@drawable/img_menu" />
<ImageButton
android:id="@+id/btn_back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="10dp"
android:background="@android:color/transparent"
android:src="@drawable/back"
android:visibility="gone" />
<LinearLayout
android:id="@+id/ll_control"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginRight="10dp"
android:gravity="center"
android:orientation="horizontal"
android:visibility="gone" >
<ImageButton
android:id="@+id/btn_text_size"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="10dp"
android:background="@android:color/transparent"
android:src="@drawable/icon_textsize" />
<ImageButton
android:id="@+id/btn_share"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@android:color/transparent"
android:src="@drawable/icon_share" />
</LinearLayout>
<ImageButton
android:id="@+id/btn_show"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginRight="10dp"
android:background="@android:color/transparent"
android:src="@drawable/icon_pic_grid_type"
android:visibility="gone" />
</RelativeLayout>
<FrameLayout
android:id="@+id/fl_content"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" >
</FrameLayout>
</LinearLayout></span>
f.创建五个Pager继承BasePager,在BasePager中初始FrameLayout,在子类中向FrameLayout添加布局
public class HomePager extends BasePager {
public HomePager(Activity mActivity) {
super(mActivity);
}
public void initdata() {
tv_title.setText("智慧北京");
btn_menu.setVisibility(View.GONE);
TextView tv1 = new TextView(mActivity);
tv1.setText("首页");
tv1.setTextSize(25);
tv1.setTextColor(Color.RED);
tv1.setGravity(Gravity.CENTER);
fl_content.addView(tv1);
}
}
(7)为了防止ViewPager滑动,重写ViewPager,OnTouch事件什么也不做
/**
* 自定义无法滑动的ViewPager
*
* @author Kevin
*
*/
public class NoScrollViewPager extends ViewPager {
public NoScrollViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
public NoScrollViewPager(Context context) {
super(context);
}
/**
* 表示不对事件进行拦截, 从而可以使嵌套在ViewPager内部的ViewPager可以响应滑动动作
*
* @param arg0
* @return
*/
@Override
public boolean onInterceptTouchEvent(MotionEvent arg0) {
return false;
}
/**
* 拦截ViewPager的触摸事件, 不做任何处理
*/
@Override
public boolean onTouchEvent(MotionEvent arg0) {
return false;
}
}
(8)页面的切换,通过RadioGroup的监听,使ViewPager贴换
// 监听RadioGroup的选中事件,对页面进行切换
mRadioGroup.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
switch (checkedId) {
case R.id.rb_home:
mViewPager.setCurrentItem(0, false);// 让ViewPager切换到第一个页面
setSlidingMenuEnable(false);
break;
case R.id.rb_news:
mViewPager.setCurrentItem(1, false);
setSlidingMenuEnable(true);
break;
case R.id.rb_service:
mViewPager.setCurrentItem(2, false);
setSlidingMenuEnable(true);
break;
case R.id.rb_gov:
mViewPager.setCurrentItem(3, false);
setSlidingMenuEnable(true);
break;
case R.id.rb_setting:
mViewPager.setCurrentItem(4, false);
setSlidingMenuEnable(false);
break;
default:
break;
}
}
});
(9)禁掉侧边栏(通过获取Activity对象从而获取SlideingMenu对象)
private void setSlidingMenuEnable(boolean enable) {
MainActivity mainUI = (MainActivity) mActivity;
SlidingMenu slidingMenu = mainUI.getSlidingMenu();
if (enable) {
slidingMenu.setTouchModeAbove(SlidingMenu.TOUCHMODE_FULLSCREEN);
} else {
slidingMenu.setTouchModeAbove(SlidingMenu.TOUCHMODE_NONE);
}
}
(10)ViewPager会默认预加载三个页面内,即执行三次(gerView)
所以加载数据最好不放在getView中,否则会预加载下一个页面
****通过监听ViewPager哪个页面被选中,从而加载数据
// 监听ViewPager的选中事件
mViewPager.setOnPageChangeListener(new OnPageChangeListener() {
@Override
public void onPageSelected(int position) {
mPagerList.get(position).initData();// 当该页面选中时,才开始初始化当前页面的数据
}
@Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
}
@Override
public void onPageScrollStateChanged(int arg0) {
}
});
mPagerList.get(0).initData();// 初始化第一页的数据
6.网络数据
1.把全局数据放在一个类中,方便控制
/**
* 定义全局常量
* @author Kevin
*
*/
public class GlobalContants {
//public static final String SERVER_URL = "http://zhihuibj.sinaapp.com/zhbj";//服务器线上前缀地址
public static final String SERVER_URL = "http://10.0.2.2:8080/zhbj";//服务器测试前缀地址
public static final String NEWS_URL = SERVER_URL + "/categories.json";//新闻中心地址
public static final String PHOTOS_URL = SERVER_URL + "/photos/photos_1.json";//组图地址
}
2.使用XUtils从网络上获取数据(加权限)
/**
* 从网络获取数据
*/
private void getDataFromNet() {
HttpUtils utils = new HttpUtils();
// RequestCallBack的泛型表示返回的数据类型, 在此我们只需要json的字符串文本, 所以传递String就可以
utils.send(HttpMethod.GET, GlobalContants.NEWS_URL,
new RequestCallBack<String>() {
// 请求成功
@Override
public void onSuccess(ResponseInfo<String> responseInfo) {
String result = responseInfo.result;
Log.d(TAG, "网络Json数据: " + result);
CacheUtils.setCache(mActivity, GlobalContants.NEWS_URL,
result);
processData(result); //解析数据
}
// 请求失败
@Override
public void onFailure(HttpException error, String msg) {
Log.e(TAG, "请求失败:" + msg);
error.printStackTrace();
}
});
}
3.使用Gson解析数据
(1)使用Bean类接收解析数据,变量名一定要一样
(2)String可以接收Int型
/**
* 网络分类信息的封装
*
* 字段名字必须和服务器返回的字段名一致, 方便gson解析
*
* @author Kevin
*
*/
public class NewsData {
public int retcode;
public ArrayList<NewsMenuData> data;
// 侧边栏数据对象
public class NewsMenuData {
public String id;
public String title;
public int type;
public String url;
public ArrayList<NewsTabData> children;
@Override
public String toString() {
return "NewsMenuData [title=" + title + ", children=" + children
+ "]";
}
}
// 新闻页面下11个子页签的数据对象
public class NewsTabData {
public String id;
public String title;
public int type;
public String url;
@Override
public String toString() {
return "NewsTabData [title=" + title + "]";
}
}
@Override
public String toString() {
return "NewsData [data=" + data + "]";
}
}
(4)解析数据
Gson gson = new Gson();
NewsData news=gson.fromJson(result, NewsData.class);
7.侧拉栏数据的填充
(1)数据在NewCenterPager中通过联网获得,ContentFragment想获得数据(也可以通过联网获得,但费资源),通过MainActivity为媒介获得数据。
(2)NewCenterPager通过MainActivity获得ContentFragment的对象
(3)在Activity中获得Fragment
// 获取侧边栏fragment
public LeftMenuFragment getLeftMenuFragment() {
FragmentManager fm = getSupportFragmentManager();
LeftMenuFragment fragment = (LeftMenuFragment) fm
.findFragmentByTag(FRAGMENT_LEFT_MENU);
return fragment;
}
创建时设置了标记tag
transaction.replace(R.id.fl_left_menu, new LeftMenuFragment(),
FRAGMENT_LEFT_MENU);// 用fragment替换framelayout
8.布局细节
(1)ListView item点击效果 android:listSelector="@android:color/transparent"
(2)ListView去掉分割线:android:divider="@android:color/transparent"
(3)点击改变颜色,使用选择器
<item android:state_enabled="true" android:drawable="@drawable/menu_arr_select"/>
<item android:drawable="@drawable/menu_arr_normal"/>
android:enabled="false" :是否可以点击
在代码中动态改变,setenable
listView点击事件
listmenu.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
long arg3) {
mCurrentPos=arg2;
myAdapter.notifyDataSetChanged();
}
});
由适配器改变视图
@Override
public View getView(int arg0, View arg1, ViewGroup arg2) {
item = View.inflate(mactivity, R.layout.list_menu_item, null);
tv_title = (TextView) item.findViewById(R.id.tv_title);
NewsMenuData newsdata = data.get(arg0);
tv_title.setText(newsdata.title);
if(mCurrentPos==arg0){
tv_title.setEnabled(true);
}else{
tv_title.setEnabled(false);
}
return item;
}
9.点击侧边栏切换页面
(1)动态向FrameLayout中添加布局
(2)添加时记得移除其他页面,removeAllView()
(3)菜单详情页基类
/**
* 菜单详情页基类
*
* @author Kevin
*
*/
public abstract class BaseMenuDetailPager {
public Activity mActivity;
public View mRootView;// 根布局对象
public BaseMenuDetailPager(Activity activity) {
mActivity = activity;
mRootView = initViews();
}
/**
* 初始化界面
*/
public abstract View initViews();
/**
* 初始化数据
*/
public void initData() {
}
}
(4)菜单详情页
/**
* 菜单详情页-互动
*
* @author Kevin
*
*/
public class InteractMenuDetailPager extends BaseMenuDetailPager {
public InteractMenuDetailPager(Activity activity) {
super(activity);
}
@Override
public View initViews() {
TextView text = new TextView(mActivity);
text.setText("菜单详情页-互动");
text.setTextColor(Color.RED);
text.setTextSize(25);
text.setGravity(Gravity.CENTER);
return text;
}
}
9.通过MainActivity传递数据-----切换新闻详情页
(1)LeftMenuFragment中
/**
* 设置当前菜单详情页
*
* @param position
*/
protected void setCurrentMenuDetailPager(int position) {
MainActivity mainUi = (MainActivity) mActivity;
ContentFragment fragment = mainUi.getContentFragment();// 获取主页面fragment
NewsCenterPager pager = fragment.getNewsCenterPager();// 获取新闻中心页面
pager.setCurrentMenuDetailPager(position);// 设置当前菜单详情页
}
(2)MainActivity中
// 获取主页面fragment
public ContentFragment getContentFragment() {
FragmentManager fm = getSupportFragmentManager();
ContentFragment fragment = (ContentFragment) fm
.findFragmentByTag(FRAGMENT_CONTENT);
return fragment;
}
(3)ContentFragment中
/**
* 获取新闻中心页面
*
* @return
*/
public NewsCenterPager getNewsCenterPager() {
return (NewsCenterPager) mPagerList.get(1);
}
(4)NewsCenterPager中
/**
* 设置当前详情页面
*
* @param position
*/
public void setCurrentDetailPager(int position) {
Log.d(TAG, "详情页面:" + position);
BaseMenuDetailPager detailPager = mMenuDetailPagers.get(position);
if (detailPager instanceof PhotosMenuDetailPager) {// 如果是组图页面,就展示组图切换按钮
btnPhotoSwitch.setVisibility(View.VISIBLE);
} else {
btnPhotoSwitch.setVisibility(View.GONE);
}
flContent.removeAllViews();// 填充界面前,先把以前的界面清空
flContent.addView(detailPager.mRootView);// 添加当前详情页的布局
detailPager.initData();// 初始化数据
tvTitle.setText(mLeftMenuList.get(position).title);
}
10.切换SlidMenu的状态
/**
* 切换SlidingMenu的状态
*
* @param b
*/
protected void toggleSlidingMenu() {
MainActivity mainUi = (MainActivity) mActivity;
SlidingMenu slidingMenu = mainUi.getSlidingMenu();
slidingMenu.toggle();// 切换状态, 显示时隐藏, 隐藏时显示
}
11.initView() & initData() 尽量分离,加载数据时会消耗资源,应在适当的位置调用
12.android.support.v4.view.ViewPager
13.initView()使用根布局对象,否则有时会报错
/**
* 菜单详情页基类
*
* @author Kevin
*
*/
public abstract class BaseMenuDetailPager {
public Activity mActivity;
public View mRootView;// 根布局对象
public BaseMenuDetailPager(Activity activity) {
mActivity = activity;
mRootView = initViews();
}
/**
* 初始化界面
*/
public abstract View initViews();
/**
* 初始化数据
*/
public void initData() {
}
}
14.嵌套ViewPager时,父控件会拦截点击事件,重写时
/**
* 不能左右划的ViewPager
*
* @author Kevin
*
*/
public class NoScrollViewPager extends ViewPager {
public NoScrollViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
public NoScrollViewPager(Context context) {
super(context);
}
// 表示事件是否拦截, 返回false表示不拦截
@Override
public boolean onInterceptTouchEvent(MotionEvent arg0) {
return false;
}
/**
* 重写onTouchEvent事件,什么都不用做
*/
@Override
public boolean onTouchEvent(MotionEvent arg0) {
return false;
}
}
15.不写get set方法也可以,反而加快速度
16.ViewPagerIndicator的使用
(1)应用某个功能,找到界面某个关键字,全局搜索Search--File Search
(2)SampleTabsDefault.java
(3)布局
<?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="match_parent"
android:orientation="vertical" >
<com.viewpagerindicator.TabPageIndicator
android:id="@+id/indicator"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
<android.support.v4.view.ViewPager
android:id="@+id/vp_menu_detail"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
(4)使用
class MenuDetailAdapter extends PagerAdapter {
/**
* 重写此方法,返回页面标题,用于viewpagerIndicator的页签显示
*/
@Override
public CharSequence getPageTitle(int position) {
return mNewsTabData.get(position).title;
}
@Override
public int getCount() {
return mPagerList.size();
}
@Override
public boolean isViewFromObject(View arg0, Object arg1) {
return arg0 == arg1;
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
TabDetailPager pager = mPagerList.get(position);
container.addView(pager.mRootView);
pager.initData();
return pager.mRootView;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
}
mViewPager.setAdapter(new MenuDetailAdapter());
mIndicator.setViewPager(mViewPager);// 将viewpager和mIndicator关联起来,必须在viewpager设置完adapter后才能调用
17.ViewPagerIndicator样式修改&切换下个页面
(1)样式不一样,可能Activity的样式不同(不是系统,是Library中的定义的)
android:theme="@style/Theme.PageIndicatorDefaults"
(2)改变整个Activity的背景色
android:background="#ffffff"
(3)修改样式
进入样式进行修改,直接修改样式
(4)控件背景变透明: android:background="@android:color/transparent"
(5)切换下个页面
<span style="font-size:14px;"> public void onClick(View arg0) {
int currentItem = viewpager.getCurrentItem();
viewpager.setCurrentItem(++currentItem);
}</span>
18.滑动事件的处理
(1)问题:向左滑动时会把侧边栏拉出,滑动事件被父控件拦截掉
(2)修改TabPageIndicator的代码 Ctrl+shift+t 查找具体类
(3)
//事件分发,请求父控件及祖宗控件不要拦截事件
public boolean dispatchTouchEvent(MotionEvent ev){
getParent().requestDisallowInterceptTouchEvent(true);
return super.dispatchTouchEvent(ev);
}
判断是否为第一个页面,如果是就拦截
/**
* 事件分发, 请求父控件及祖宗控件是否拦截事件
*/
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (getCurrentItem() != 0) {
getParent().requestDisallowInterceptTouchEvent(true);// 用getParent去请求,
// 不拦截
} else {// 如果是第一个页面,需要显示侧边栏, 请求父控件拦截
getParent().requestDisallowInterceptTouchEvent(false);// 拦截
}
return super.dispatchTouchEvent(ev);
}
(4)Touch机制的处理
http://www.cnblogs.com/jqyp/archive/2012/04/25/2469758.html
(5)页签详情页的ViewPager也无法向左滑动,被父控件拦截了,同理自定义一个ViewPager,请求父控件不要拦截事件
19.头条新闻展示&BitmapUtils
(1)获取网络数据
/*
* 获取网络数据
*/
private void getDataFromServer() {
HttpUtils utils = new HttpUtils();
utils.send(HttpMethod.GET, mUrl, new RequestCallBack<String>() {
@Override
public void onSuccess(ResponseInfo<String> responseInfo) {
String result = (String) responseInfo.result;
System.out.println("页签详情页返回结果:" + result);
parseData(result); // 解析Json
}
@Override
public void onFailure(HttpException error, String msg) {
Toast.makeText(mActivity, msg, Toast.LENGTH_SHORT).show();
error.printStackTrace();
}
});
}
(2)解析数据
数据接收类--------------变量名必须一样,靠变量名接收
/**
* 页签详情页数据
*
* @author Kevin
*
*/
public class TabData {
public int retcode;
public TabDetail data;
public class TabDetail {
public String title;
public String more;
public ArrayList<TabNewsData> news;
public ArrayList<TopNewsData> topnews;
@Override
public String toString() {
return "TabDetail [title=" + title + ", news=" + news
+ ", topnews=" + topnews + "]";
}
}
/**
* 新闻列表对象
*
* @author Kevin
*
*/
public class TabNewsData {
public String id;
public String listimage;
public String pubdate;
public String title;
public String type;
public String url;
@Override
public String toString() {
return "TabNewsData [title=" + title + "]";
}
}
/**
* 头条新闻
*
* @author Kevin
*
*/
public class TopNewsData {
public String id;
public String topimage;
public String pubdate;
public String title;
public String type;
public String url;
@Override
public String toString() {
return "TopNewsData [title=" + title + "]";
}
}
@Override
public String toString() {
return "TabData [data=" + data + "]";
}
}
接收
Gson gson = new Gson();
mTabDetailData = gson.fromJson(result, TabData.class);
System.out.println("页签详情解析:" + mTabDetailData);
(3) image.setScaleType()//指定图片是否填充ImageView
(4)使用BitmapUtil
public class TopNewsAdapter extends PagerAdapter {
private BitmapUtils utils;
public TopNewsAdapter() {
utils = new BitmapUtils(mActivity);
utils.configDefaultLoadingImage(R.drawable.topnews_item_default);// 设置默认图片
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return topnews.size();
}
@Override
public boolean isViewFromObject(View arg0, Object arg1) {
// TODO Auto-generated method stub
return arg0 == arg1;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
ImageView image = new ImageView(mActivity);
TopNewsData topNewsData = topnews.get(position);//
utils.display(image, topNewsData.topimage);// 传递imagView对象和图片地址
System.out.println(topNewsData.topimage);
container.addView(image);
return image;
}
}
(5) image.setScaleType()//指定图片是否填充ImageView
19.智慧北京事件处理及总结--------------------------------重新优化滑动触摸事件
(1)事件发生矛盾无法解决,使用另外的思路
对ViewPager进行监听,禁掉SlidingMenu
(2)新闻详情页(11个ViewPager),对ViewPager进行监听,由于与TabPageIndicator进行绑定,使用是对TabPageIndicator进行监听
//***父类implements OnPageChangeListener
// mViewPager.setOnPageChangeListener(this);//注意:当viewpager和Indicator绑定时,
// 滑动监听需要设置给Indicator而不是viewpager
mIndicator.setOnPageChangeListener(this);
//进行监听
@Override
public void onPageScrollStateChanged(int arg0) {
}
@Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
}
@Override
public void onPageSelected(int arg0) {
System.out.println("onPageSelected:" + arg0);
MainActivity mainUi = (MainActivity) mActivity;
SlidingMenu slidingMenu = mainUi.getSlidingMenu();
if (arg0 == 0) {//只有在第一个页面(北京), 侧边栏才允许出来
slidingMenu.setTouchModeAbove(SlidingMenu.TOUCHMODE_FULLSCREEN);
} else {
slidingMenu.setTouchModeAbove(SlidingMenu.TOUCHMODE_NONE);
}
}
(3)重写TopNewsViewPager,判断滑动事件
分析:1.右滑,第一页面,需要父控件拦截
2.左滑,最后一个页面,需要父控件拦截
3.上下滑,需要父控件拦截
/**
* 头条新闻的Viewpager
*
* @author Kevin
*
*/
public class TopNewsViewPager extends ViewPager {
int startX;
int startY;
public TopNewsViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
public TopNewsViewPager(Context context) {
super(context);
}
/**
* 事件分发, 请求父控件及祖宗控件是否拦截事件 1. 右划, 而且是第一个页面, 需要父控件拦截 2. 左划, 而且是最后一个页面, 需要父控件拦截
* 3. 上下滑动, 需要父控件拦截
*/
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
getParent().requestDisallowInterceptTouchEvent(true);// 不要拦截,
// 这样是为了保证ACTION_MOVE调用
startX = (int) ev.getRawX();
startY = (int) ev.getRawY();
break;
case MotionEvent.ACTION_MOVE:
int endX = (int) ev.getRawX();
int endY = (int) ev.getRawY();
if (Math.abs(endX - startX) > Math.abs(endY - startY)) {// 左右滑动
if (endX > startX) {// 右划
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);
}
}
20.头条新闻标题设置
(1)监听ViewPager的滑动
(2)优化:给CirclePageIndicator进行监听,不是对ViewPager监听,因为进行了绑定
private CirclePageIndicator mIndicator;// 头条新闻位置指示器
mIndicator.setOnPageChangeListener(this);
21.使用ViewpagerIndicator实现头条新闻位置指示器
(1)查看框架例子相应的文件,照着写
(2) 布局:
xmlns:app="http://schemas.android.com/apk/res-auto" //命名空间
//通过布局改变样式,看框架例子
<com.viewpagerindicator.CirclePageIndicator
android:id="@+id/indicator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:padding="10dip"
app:fillColor="#f00"
app:pageColor="@android:color/darker_gray"
app:radius="3dp"
app:strokeWidth="0dp" />
mIndicator.setViewPager(mViewPager);
mIndicator.setSnap(true);// 支持快照显示
mIndicator.setOnPageChangeListener(this);
mIndicator.onPageSelected(0);// 让指示器重新定位到第一个点
22.新闻列表展示&item布局编写
(1)src和background的区别
background会根据ImageView组件给定的长宽进行拉伸,而src就存放的是原图的大小,不会进行拉伸。src是图片内容(前景),bg是背景,可以同时使用。
此外:scaleType只对src起作用;bg可设置透明度,比如在ImageButton中就可以用android:scaleType控制图片的缩放方式
http://uuton.com/post/3f493_1b8753
(2)新闻item布局
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ImageView
android:id="@+id/iv_pic"
android:layout_width="110dp"
android:layout_height="70dp"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:background="@android:color/darker_gray"
android:padding="1dp"
android:scaleType="fitXY"
android:src="@drawable/image_demo" />
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_marginLeft="20dp"
android:layout_toRightOf="@+id/iv_pic"
android:ellipsize="end"
android:maxLines="2"
android:text="新闻标题新闻标题新闻标题新闻标题新闻标题新闻标题新闻标题新闻标题新闻标题新闻标题新闻标题新闻标题新闻标题新闻标题新闻标题新闻标题"
android:textColor="#000" />
<TextView
android:id="@+id/tv_date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@+id/iv_pic"
android:layout_alignLeft="@+id/tv_title"
android:text="2015-03-16 16:20"
android:textColor="@android:color/darker_gray"
android:textSize="16sp" />
</RelativeLayout>
(3)getView优化,BitmapUtil的使用
/**
* 新闻列表的适配器
*
* @author Kevin
*
*/
class NewsAdapter extends BaseAdapter {
private BitmapUtils utils;
public NewsAdapter() {
utils = new BitmapUtils(mActivity);
utils.configDefaultLoadingImage(R.drawable.pic_item_list_default);
}
@Override
public int getCount() {
return mNewsList.size();
}
@Override
public TabNewsData getItem(int position) {
return mNewsList.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = View.inflate(mActivity, R.layout.list_news_item,
null);
holder = new ViewHolder();
holder.ivPic = (ImageView) convertView
.findViewById(R.id.iv_pic);
holder.tvTitle = (TextView) convertView
.findViewById(R.id.tv_title);
holder.tvDate = (TextView) convertView
.findViewById(R.id.tv_date);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
TabNewsData item = getItem(position);
holder.tvTitle.setText(item.title);
holder.tvDate.setText(item.pubdate);
utils.display(holder.ivPic, item.listimage);
return convertView;
}
}
static class ViewHolder {
public TextView tvTitle;
public TextView tvDate;
public ImageView ivPic;
}
23.新闻列表展示&HeaderView
(1)listView滑动时出现黑色:android:cacheColorHint="#fff"
(2)把ViewPager当做头布局加到listView中
(3)动态添加头布局,把头布局提取出来
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<com.itheima.zhbj52.view.TopNewsViewPager
android:id="@+id/vp_news"
android:layout_width="match_parent"
android:layout_height="200dp" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:background="#a000"
android:padding="3dp" >
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#fff"
android:textSize="16sp" />
<com.viewpagerindicator.CirclePageIndicator
android:id="@+id/indicator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:padding="10dip"
app:fillColor="#f00"
app:pageColor="@android:color/darker_gray"
app:radius="3dp"
app:strokeWidth="0dp" />
</RelativeLayout>
</RelativeLayout>
(4)动态添加头布局
// 将头条新闻以头布局的形式加给listview
lvList.addHeaderView(headerView);
24.自定义下拉刷新
(1)public class RefreshListView extends ListView 代替ListView
(2)头布局
<?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:paddingLeft="10dp"
android:paddingRight="10dp"
android:paddingTop="10dp" >
<ImageView
android:id="@+id/iv_arr"
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_progress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:visibility="invisible" />
</FrameLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="center"
android:gravity="center"
android:orientation="vertical" >
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="下拉刷新"
android:textColor="#f00"
android:textSize="20sp" />
<TextView
android:id="@+id/tv_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="2015-03-10 17:07:07"
android:textColor="@android:color/darker_gray"
android:textSize="16sp" />
</LinearLayout>
</LinearLayout>
/**
* 下拉刷新的ListView
*
* @author Kevin
*
*/
public class RefreshListView extends ListView {
private View mHeaderView;
public RefreshListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initHeaderView();
}
public RefreshListView(Context context, AttributeSet attrs) {
super(context, attrs);
initHeaderView();
}
public RefreshListView(Context context) {
super(context);
initHeaderView();
}
/**
* 初始化头布局
*/
private void initHeaderView() {
mHeaderView = View.inflate(getContext(), R.layout.refresh_header, null);
this.addHeaderView(mHeaderView);
mHeaderView.measure(0, 0);
int mHeaderViewHeight = mHeaderView.getMeasuredHeight();
mHeaderView.setPadding(0, -mHeaderViewHeight, 0, 0);//隐藏头布局
}
}
25.下拉刷新实现
(2)改变Progress的图片
<ProgressBar
android:id="@+id/pb_progress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:indeterminateDrawable="@drawable/custom_progress"
android:visibility="invisible" />
(3)自己画一个圆环 shape
<?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="12dp"
android:shape="ring"
android:thickness="3dp"
android:useLevel="false" >
<gradient
android:centerColor="#3f00"
android:endColor="#f00"
android:startColor="#fff" />
</shape>
</rotate>
android:useLevel="false" 去掉Progress自带的动画
rotate--------------------------- 在shape中自定义一个动画
下拉刷新的实现 & 加载更多
(1)加载更多布局
<?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:gravity="center"
android:orientation="horizontal" >
<ProgressBar
android:id="@+id/pb_pull_list_header"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="5dp"
android:indeterminateDrawable="@drawable/custom_progress" />
<TextView
android:id="@+id/tv_pull_list_header_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="加载中..."
android:textColor="#ff0000"
android:textSize="18sp" />
</LinearLayout>
(2)完整ListView
/**
* 下拉刷新的ListView
*
* @author Kevin
*
*/
public class RefreshListView extends ListView implements OnScrollListener,
android.widget.AdapterView.OnItemClickListener {
private static final int STATE_PULL_REFRESH = 0;// 下拉刷新
private static final int STATE_RELEASE_REFRESH = 1;// 松开刷新
private static final int STATE_REFRESHING = 2;// 正在刷新
private View mHeaderView;
private int startY = -1;// 滑动起点的y坐标
private int mHeaderViewHeight;
private int mCurrrentState = STATE_PULL_REFRESH;// 当前状态
private TextView tvTitle;
private TextView tvTime;
private ImageView ivArrow;
private ProgressBar pbProgress;
private RotateAnimation animUp;
private RotateAnimation animDown;
public RefreshListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initHeaderView();
initFooterView();
}
public RefreshListView(Context context, AttributeSet attrs) {
super(context, attrs);
initHeaderView();
initFooterView();
}
public RefreshListView(Context context) {
super(context);
initHeaderView();
initFooterView();
}
/**
* 初始化头布局
*/
private void initHeaderView() {
mHeaderView = View.inflate(getContext(), R.layout.refresh_header, null);
this.addHeaderView(mHeaderView);
tvTitle = (TextView) mHeaderView.findViewById(R.id.tv_title);
tvTime = (TextView) mHeaderView.findViewById(R.id.tv_time);
ivArrow = (ImageView) mHeaderView.findViewById(R.id.iv_arr);
pbProgress = (ProgressBar) mHeaderView.findViewById(R.id.pb_progress);
mHeaderView.measure(0, 0);
mHeaderViewHeight = mHeaderView.getMeasuredHeight();
mHeaderView.setPadding(0, -mHeaderViewHeight, 0, 0);// 隐藏头布局
initArrowAnim();
tvTime.setText("最后刷新时间:" + getCurrentTime());
}
/*
* 初始化脚布局
*/
private void initFooterView() {
mFooterView = View.inflate(getContext(),
R.layout.refresh_listview_footer, null);
this.addFooterView(mFooterView);
mFooterView.measure(0, 0);
mFooterViewHeight = mFooterView.getMeasuredHeight();
mFooterView.setPadding(0, -mFooterViewHeight, 0, 0);// 隐藏
this.setOnScrollListener(this);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
startY = (int) ev.getRawY();
break;
case MotionEvent.ACTION_MOVE:
if (startY == -1) {// 确保startY有效
startY = (int) ev.getRawY();
}
if (mCurrrentState == STATE_REFRESHING) {// 正在刷新时不做处理
break;
}
int endY = (int) ev.getRawY();
int dy = endY - startY;// 移动便宜量
if (dy > 0 && getFirstVisiblePosition() == 0) {// 只有下拉并且当前是第一个item,才允许下拉
int padding = dy - mHeaderViewHeight;// 计算padding
mHeaderView.setPadding(0, padding, 0, 0);// 设置当前padding
if (padding > 0 && mCurrrentState != STATE_RELEASE_REFRESH) {// 状态改为松开刷新
mCurrrentState = STATE_RELEASE_REFRESH;
refreshState();
} else if (padding < 0 && mCurrrentState != STATE_PULL_REFRESH) {// 改为下拉刷新状态
mCurrrentState = STATE_PULL_REFRESH;
refreshState();
}
return true;
}
break;
case MotionEvent.ACTION_UP:
startY = -1;// 重置
if (mCurrrentState == STATE_RELEASE_REFRESH) {
mCurrrentState = STATE_REFRESHING;// 正在刷新
mHeaderView.setPadding(0, 0, 0, 0);// 显示
refreshState();
} else if (mCurrrentState == STATE_PULL_REFRESH) {
mHeaderView.setPadding(0, -mHeaderViewHeight, 0, 0);// 隐藏
}
break;
default:
break;
}
return super.onTouchEvent(ev);
}
/**
* 刷新下拉控件的布局
*/
private void refreshState() {
switch (mCurrrentState) {
case STATE_PULL_REFRESH:
tvTitle.setText("下拉刷新");
ivArrow.setVisibility(View.VISIBLE);
pbProgress.setVisibility(View.INVISIBLE);
ivArrow.startAnimation(animDown);
break;
case STATE_RELEASE_REFRESH:
tvTitle.setText("松开刷新");
ivArrow.setVisibility(View.VISIBLE);
pbProgress.setVisibility(View.INVISIBLE);
ivArrow.startAnimation(animUp);
break;
case STATE_REFRESHING:
tvTitle.setText("正在刷新...");
ivArrow.clearAnimation();// 必须先清除动画,才能隐藏
ivArrow.setVisibility(View.INVISIBLE);
pbProgress.setVisibility(View.VISIBLE);
if (mListener != null) {
mListener.onRefresh();
}
break;
default:
break;
}
}
/**
* 初始化箭头动画
*/
private void initArrowAnim() {
// 箭头向上动画
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);
}
OnRefreshListener mListener;
private View mFooterView;
private int mFooterViewHeight;
public void setOnRefreshListener(OnRefreshListener listener) {
mListener = listener;
}
public interface OnRefreshListener {
public void onRefresh();
public void onLoadMore();// 加载下一页数据
}
/*
* 收起下拉刷新的控件
*/
public void onRefreshComplete(boolean success) {
if (isLoadingMore) {// 正在加载更多...
mFooterView.setPadding(0, -mFooterViewHeight, 0, 0);// 隐藏脚布局
isLoadingMore = false;
} else {
mCurrrentState = STATE_PULL_REFRESH;
tvTitle.setText("下拉刷新");
ivArrow.setVisibility(View.VISIBLE);
pbProgress.setVisibility(View.INVISIBLE);
mHeaderView.setPadding(0, -mHeaderViewHeight, 0, 0);// 隐藏
if (success) {
tvTime.setText("最后刷新时间:" + getCurrentTime());
}
}
}
/**
* 获取当前时间
*/
public String getCurrentTime() {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return format.format(new Date());
}
private boolean isLoadingMore;
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
if (scrollState == SCROLL_STATE_IDLE
|| scrollState == SCROLL_STATE_FLING) {
if (getLastVisiblePosition() == getCount() - 1 && !isLoadingMore) {// 滑动到最后
System.out.println("到底了.....");
mFooterView.setPadding(0, 0, 0, 0);// 显示
setSelection(getCount() - 1);// 改变listview显示位置
isLoadingMore = true;
if (mListener != null) {
mListener.onLoadMore();
}
}
}
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
}
OnItemClickListener mItemClickListener;
@Override
public void setOnItemClickListener(
android.widget.AdapterView.OnItemClickListener listener) {
super.setOnItemClickListener(this);
mItemClickListener = listener;
}
@Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
if (mItemClickListener != null) {
mItemClickListener.onItemClick(parent, view, position
- getHeaderViewsCount(), id);
}
}
}
导入的包
import java.text.SimpleDateFormat;
import java.util.Date;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.RotateAnimation;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.AdapterView;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
(3)使用接口
// 设置下拉刷新监听
lv.setOnRefreshListener(new OnRefreshListener() {
@Override
public void onRefresh() {
getDataFromServer(); //下拉刷新
}
@Override
public void onLoadMore() { //加载更多
if (mMoreUrl != null) { getMoreDataFromServer(); } else {
Toast.makeText(mActivity, "最后一页了", Toast.LENGTH_SHORT)
.show(); lv.onRefreshComplete(false);// 收起加载更多的布局
}
}
});
lvList.onRefreshComplete(true); //收起头布局和脚布局
详细使用
public class TabDetailPager extends BaseMenuDetailPager implements
OnPageChangeListener {
public TextView tvText;
public NewsTabData tabData;
private String mUrl;
private TabData mTabDetailData;
private ViewPager viewpager;
public ArrayList<TopNewsData> topnews;
private TextView tv_title;
private TopNewsData topNewsData;
private CirclePageIndicator mIndicator;
private RefreshListView lv;
private ArrayList<TabNewsData> mNewsList; // 新闻数据集合
private String mMoreUrl;// 更多页面的地址
private NewsAdapter mNewsAdapter;
public TabDetailPager(Activity aActivity, NewsTabData newsTabData) {
super(aActivity);
tabData = newsTabData;
mUrl = GlobalContans.SERVER_URL + tabData.url;
System.out.println(mUrl);
}
@Override
public View initView() {
View view = View.inflate(mActivity, R.layout.tab_detail_pager, null);
View headview = View.inflate(mActivity, R.layout.list_header_topnews,
null);
viewpager = (ViewPager) headview.findViewById(R.id.viewpager);
tv_title = (TextView) headview.findViewById(R.id.tv_title);
mIndicator = (CirclePageIndicator) headview
.findViewById(R.id.indicator);
lv = (RefreshListView) view.findViewById(R.id.lv);
lv.addHeaderView(headview);
// 设置下拉刷新监听
lv.setOnRefreshListener(new OnRefreshListener() {
@Override
public void onRefresh() {
getDataFromServer();
}
@Override
public void onLoadMore() {
if (mMoreUrl != null) { getMoreDataFromServer(); } else {
Toast.makeText(mActivity, "最后一页了", Toast.LENGTH_SHORT)
.show(); lv.onRefreshComplete(false);// 收起加载更多的布局
}
}
});
return view;
}
@Override
public void initdata() {
getDataFromServer();
}
/*
* 获取网络数据
*/
private void getDataFromServer() {
HttpUtils utils = new HttpUtils();
utils.send(HttpMethod.GET, mUrl, new RequestCallBack<String>() {
@Override
public void onSuccess(ResponseInfo<String> responseInfo) {
String result = (String) responseInfo.result;
parseData(result,false); // 解析Json
lv.onRefreshComplete(true);
}
@Override
public void onFailure(HttpException error, String msg) {
Toast.makeText(mActivity, msg, Toast.LENGTH_SHORT).show();
error.printStackTrace();
lv.onRefreshComplete(true);
}
});
}
/**
* 加载下一页数据
*/
private void getMoreDataFromServer() {
HttpUtils utils = new HttpUtils();
utils.send(HttpMethod.GET, mMoreUrl, new RequestCallBack<String>() {
@Override
public void onSuccess(ResponseInfo<String> responseInfo) {
String result = (String) responseInfo.result;
parseData(result, true);
lv.onRefreshComplete(true);
}
@Override
public void onFailure(HttpException error, String msg) {
Toast.makeText(mActivity, msg, Toast.LENGTH_SHORT).show();
error.printStackTrace();
lv.onRefreshComplete(false);
}
});
}
/*
* 解析数据
*/
protected void parseData(String result,boolean isMore) {
Gson gson = new Gson();
mTabDetailData = gson.fromJson(result, TabData.class);
String more = mTabDetailData.data.more;
if (!TextUtils.isEmpty(more)) {
mMoreUrl = GlobalContans.SERVER_URL + more;
} else {
mMoreUrl = null;
}
if (!isMore) {
topnews = new ArrayList<TopNewsData>();
topnews = mTabDetailData.data.topnews;
mNewsList = mTabDetailData.data.news;
// System.out.println(topnews.toString());
viewpager.setAdapter(new TopNewsAdapter());
mIndicator.setViewPager(viewpager);
mIndicator.setSnap(true);// 支持快照显示
mIndicator.setOnPageChangeListener(this);
mIndicator.onPageSelected(0);// 让指示器重新定位到第一个点
topNewsData = topnews.get(0);
tv_title.setText(topNewsData.title);
mNewsAdapter=new NewsAdapter();
lv.setAdapter(mNewsAdapter);
}else{
ArrayList<TabNewsData> news = mTabDetailData.data.news;
mNewsList.addAll(news);
mNewsAdapter.notifyDataSetChanged();
}
}
public class TopNewsAdapter extends PagerAdapter {
private BitmapUtils utils;
public TopNewsAdapter() {
utils = new BitmapUtils(mActivity);
utils.configDefaultLoadingImage(R.drawable.topnews_item_default);// 设置默认图片
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return topnews.size();
}
@Override
public boolean isViewFromObject(View arg0, Object arg1) {
// TODO Auto-generated method stub
return arg0 == arg1;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
ImageView image = new ImageView(mActivity);
image.setScaleType(ScaleType.FIT_XY);// 基于控件大小填充图片
topNewsData = topnews.get(position);//
utils.display(image, topNewsData.topimage);// 传递imagView对象和图片地址
// System.out.println(topNewsData.topimage);
container.addView(image);
return image;
}
}
/*
* ListView的适配器
*/
public class NewsAdapter extends BaseAdapter {
private BitmapUtils utils;
public NewsAdapter() {
utils = new BitmapUtils(mActivity);
utils.configDefaultLoadingImage(R.drawable.pic_item_list_default);
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return mNewsList.size();
}
@Override
public Object getItem(int arg0) {
// TODO Auto-generated method stub
return null;
}
@Override
public long getItemId(int arg0) {
// TODO Auto-generated method stub
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = View.inflate(mActivity, R.layout.list_news_item,
null);
holder = new ViewHolder();
holder.ivPic = (ImageView) convertView
.findViewById(R.id.iv_pic);
holder.tvTitle = (TextView) convertView
.findViewById(R.id.tv_title);
holder.tvDate = (TextView) convertView
.findViewById(R.id.tv_date);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
TabNewsData item = mNewsList.get(position);
holder.tvTitle.setText(item.title);
holder.tvDate.setText(item.pubdate);
utils.display(holder.ivPic, item.listimage);
return convertView;
}
}
static class ViewHolder {
public TextView tvTitle;
public TextView tvDate;
public ImageView ivPic;
}
/*
* 监听ViewPager的滑动
*/
@Override
public void onPageScrollStateChanged(int arg0) {
// TODO Auto-generated method stub
}
@Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
// TODO Auto-generated method stub
}
@Override
public void onPageSelected(int position) {
topNewsData = topnews.get(position);
tv_title.setText(topNewsData.title);
}
}
26.listview点击封装&标记已读
(1)ListView的点击事件,因为要减去头布局,所以把点击事件封装到自定义ListView中(也可以不这样写)
OnItemClickListener mItemClickListener;
@Override
public void setOnItemClickListener(
android.widget.AdapterView.OnItemClickListener listener) {
super.setOnItemClickListener(this);
mItemClickListener = listener;
}
@Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
if (mItemClickListener != null) {
mItemClickListener.onItemClick(parent, view, position
- getHeaderViewsCount(), id);
}
}
使用:
lvList.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
}
});
这样使用不用减去头布局的数量,直接用
(2)标记已读,记录新闻的Id
lvList.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
//返回的view为点击的item,可以使用该view找到item中的控件id,从而改变控件的状态
// mNewsAdapter.notifyDataSetChanged();,不使用这种,浪费性能
changeReadState(view);// 实现局部界面刷新, 这个view就是被点击的item布局对象
}
});
/**
* 改变已读新闻的颜色
*/
private void changeReadState(View view) {
TextView tvTitle = (TextView) view.findViewById(R.id.tv_title);
tvTitle.setTextColor(Color.GRAY);
}
第一次加载时,在geiview中也要判断
String ids = PrefUtils.getString(mActivity, "read_ids", "");
if (ids.contains(getItem(position).id)) {
holder.tvTitle.setTextColor(Color.GRAY);
} else {
holder.tvTitle.setTextColor(Color.BLACK);
}
27.新闻详情页&Webview介绍
(1)Intent带数据跳转
// 跳转新闻详情页
Intent intent = new Intent();
intent.setClass(mActivity, NewsDetailActivity.class);
intent.putExtra("url", mNewsList.get(position).url);
mActivity.startActivity(intent);
接收:String url = getIntent().getStringExtra("url");
(2)WebView的使用见之前写的笔记
28.ShareSDK
(1)详情见前面的或视频
29.缓存介绍------xutils会自动缓存图片
(1)创建缓存工具类
/**
* 缓存工具类
*
* @author Kevin
*
*/
public class CacheUtils {
/**
* 设置缓存 key 是url, value是json
*/
public static void setCache(String key, String value, Context ctx) {
PrefUtils.setString(ctx, key, value);
//可以将缓存放在文件中, 文件名就是Md5(url), 文件内容是json
}
/**
* 获取缓存 key 是url
*/
public static String getCache(String key, Context ctx) {
return PrefUtils.getString(ctx, key, null);
}
}
PrefUtils
/**
* SharePreference封装
*
* @author Kevin
*
*/
public class PrefUtils {
public static final String PREF_NAME = "config";
public static boolean getBoolean(Context ctx, String key,
boolean defaultValue) {
SharedPreferences sp = ctx.getSharedPreferences(PREF_NAME,
Context.MODE_PRIVATE);
return sp.getBoolean(key, defaultValue);
}
public static void setBoolean(Context ctx, String key, boolean value) {
SharedPreferences sp = ctx.getSharedPreferences(PREF_NAME,
Context.MODE_PRIVATE);
sp.edit().putBoolean(key, value).commit();
}
public static String getString(Context ctx, String key, String defaultValue) {
SharedPreferences sp = ctx.getSharedPreferences(PREF_NAME,
Context.MODE_PRIVATE);
return sp.getString(key, defaultValue);
}
public static void setString(Context ctx, String key, String value) {
SharedPreferences sp = ctx.getSharedPreferences(PREF_NAME,
Context.MODE_PRIVATE);
sp.edit().putString(key, value).commit();
}
}
(2)把整个Json缓存下来
a.区分不同的Json,用Json的URl标识
@Override
public void initData() {
System.out.println("初始化新闻中心数据....");
tvTitle.setText("新闻");
setSlidingMenuEnable(true);// 打开侧边栏
String cache = CacheUtils.getCache(GlobalContants.CATEGORIES_URL,
mActivity);
if (!TextUtils.isEmpty(cache)) {// 如果缓存存在,直接解析数据, 无需访问网路
parseData(cache);
}
getDataFromServer();// 不管有没有缓存, 都获取最新数据, 保证数据最新
}
解析完数据设置缓存
parseData(result);
// 设置缓存
CacheUtils.setCache(GlobalContants.CATEGORIES_URL,
result, mActivity);
30.自动轮播条
(1)使用Handler
(2)在解析完数据时使用Handler
private Handler mHandler;
// 自动轮播条显示
if (mHandler == null) {
mHandler = new Handler() {
public void handleMessage(android.os.Message msg) {
int currentItem = mViewPager.getCurrentItem();
if (currentItem < mTopNewsList.size() - 1) {
currentItem++;
} else {
currentItem = 0;
}
mViewPager.setCurrentItem(currentItem);// 切换到下一个页面
mHandler.sendEmptyMessageDelayed(0, 3000);// 继续延时3秒发消息,
// 形成循环
};
};
mHandler.sendEmptyMessageDelayed(0, 3000);// 延时3秒后发消息
}
31.轮播条触摸监听
1.在适配器中设置点击事件
image.setOnTouchListener(new TopNewsTouchListener());//设置触摸监听
/**
* 头条新闻的触摸监听
*
* @author Kevin
*
*/
class TopNewsTouchListener implements OnTouchListener {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
System.out.println("按下");
mHandler.removeCallbacksAndMessages(null);// 删除Handler中的所有消息
// mHandler.postDelayed(new Runnable() {
//
// @Override
// public void run() {
//
// }
// }, 3000);
break;
case MotionEvent.ACTION_CANCEL:
System.out.println("事件取消");
mHandler.sendEmptyMessageDelayed(0, 3000);
break;
case MotionEvent.ACTION_UP:
System.out.println("抬起");
mHandler.sendEmptyMessageDelayed(0, 3000);
break;
default:
break;
}
return true;
}
}
32.组图模块开发
(1)布局
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ListView
android:id="@+id/lv_photo"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:cacheColorHint="#fff"
android:divider="@null" />
<GridView
android:id="@+id/gv_photo"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:numColumns="2"
android:visibility="gone" />
</FrameLayout>
(2)GridView与ListView切换
/**
* 菜单详情页-组图
*
* @author Kevin
*
*/
public class PhotoMenuDetailPager extends BaseMenuDetailPager {
private ListView lvPhoto;
private GridView gvPhoto;
private ArrayList<PhotoInfo> mPhotoList;
private PhotoAdapter mAdapter;
private ImageButton btnPhoto;
public PhotoMenuDetailPager(Activity activity, ImageButton btnPhoto) {
super(activity);
this.btnPhoto = btnPhoto;
btnPhoto.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
changeDisplay();
}
});
}
@Override
public View initViews() {
View view = View.inflate(mActivity, R.layout.menu_photo_pager, null);
lvPhoto = (ListView) view.findViewById(R.id.lv_photo);
gvPhoto = (GridView) view.findViewById(R.id.gv_photo);
return view;
}
@Override
public void initData() {
String cache = CacheUtils
.getCache(GlobalContants.PHOTOS_URL, mActivity);
if (!TextUtils.isEmpty(cache)) {
}
getDataFromServer();
}
private void getDataFromServer() {
HttpUtils utils = new HttpUtils();
utils.send(HttpMethod.GET, GlobalContants.PHOTOS_URL,
new RequestCallBack<String>() {
@Override
public void onSuccess(ResponseInfo<String> responseInfo) {
String result = (String) responseInfo.result;
parseData(result);
// 设置缓存
CacheUtils.setCache(GlobalContants.PHOTOS_URL, result,
mActivity);
}
@Override
public void onFailure(HttpException error, String msg) {
Toast.makeText(mActivity, msg, Toast.LENGTH_SHORT)
.show();
error.printStackTrace();
}
});
}
protected void parseData(String result) {
Gson gson = new Gson();
PhotosData data = gson.fromJson(result, PhotosData.class);
mPhotoList = data.data.news;// 获取组图列表集合
if (mPhotoList != null) {
mAdapter = new PhotoAdapter();
lvPhoto.setAdapter(mAdapter);
gvPhoto.setAdapter(mAdapter);
}
}
class PhotoAdapter extends BaseAdapter {
private BitmapUtils utils;
public PhotoAdapter() {
utils = new BitmapUtils(mActivity);
utils.configDefaultLoadingImage(R.drawable.news_pic_default);
}
@Override
public int getCount() {
return mPhotoList.size();
}
@Override
public PhotoInfo getItem(int position) {
return mPhotoList.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
convertView = View.inflate(mActivity, R.layout.list_photo_item,
null);
holder = new ViewHolder();
holder.tvTitle = (TextView) convertView
.findViewById(R.id.tv_title);
holder.ivPic = (ImageView) convertView
.findViewById(R.id.iv_pic);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
PhotoInfo item = getItem(position);
holder.tvTitle.setText(item.title);
utils.display(holder.ivPic, item.listimage);
return convertView;
}
}
static class ViewHolder {
public TextView tvTitle;
public ImageView ivPic;
}
private boolean isListDisplay = true;// 是否是列表展示
/**
* 切换展现方式
*/
private void changeDisplay() {
if (isListDisplay) {
isListDisplay = false;
lvPhoto.setVisibility(View.GONE);
gvPhoto.setVisibility(View.VISIBLE);
btnPhoto.setImageResource(R.drawable.icon_pic_list_type);
} else {
isListDisplay = true;
lvPhoto.setVisibility(View.VISIBLE);
gvPhoto.setVisibility(View.GONE);
btnPhoto.setImageResource(R.drawable.icon_pic_grid_type);
}
}
}
33.三级缓存原理
(1)原理
- 内存缓存, 优先加载, 速度最快
- 本地缓存, 次优先加载, 速度快
- 网络缓存, 不优先加载, 速度慢,浪费流量
34.网络缓存&AsyncTask
(1)AsyncTask的使用
a.三个主要方法以及在什么线程中执行
(2)网络缓存,下载后往本地和内存添加一份
/**
* 网络缓存
*
* @author Kevin
*
*/
public class NetCacheUtils {
private LocalCacheUtils mLocalCacheUtils;
private MemoryCacheUtils mMemoryCacheUtils;
public NetCacheUtils(LocalCacheUtils localCacheUtils,
MemoryCacheUtils memoryCacheUtils) {
mLocalCacheUtils = localCacheUtils;
mMemoryCacheUtils = memoryCacheUtils;
}
/**
* 从网络下载图片
*
* @param ivPic
* @param url
*/
public void getBitmapFromNet(ImageView ivPic, String url) {
new BitmapTask().execute(ivPic, url);// 启动AsyncTask,
// 参数会在doInbackground中获取
}
/**
* Handler和线程池的封装
*
* 第一个泛型: 参数类型 第二个泛型: 更新进度的泛型, 第三个泛型是onPostExecute的返回结果
*
* @author Kevin
*
*/
class BitmapTask extends AsyncTask<Object, Void, Bitmap> {
private ImageView ivPic;
private String url;
/**
* 后台耗时方法在此执行, 子线程
*/
@Override
protected Bitmap doInBackground(Object... params) {
ivPic = (ImageView) params[0];
url = (String) params[1];
ivPic.setTag(url);// 将url和imageview绑定,确保图片设定给了正确的imageview
return downloadBitmap(url);
}
/**
* 更新进度, 主线程
*/
@Override
protected void onProgressUpdate(Void... values) {
super.onProgressUpdate(values);
}
/**
* 耗时方法结束后,执行该方法, 主线程
*/
@Override
protected void onPostExecute(Bitmap result) {
if (result != null) {
String bindUrl = (String) ivPic.getTag();
if (url.equals(bindUrl)) {// 确保图片设定给了正确的imageview
ivPic.setImageBitmap(result);
mLocalCacheUtils.setBitmapToLocal(url, result);// 将图片保存在本地
mMemoryCacheUtils.setBitmapToMemory(url, result);// 将图片保存在内存
System.out.println("从网络缓存读取图片啦...");
}
}
}
}
/**
* 下载图片
*
* @param url
* @return
*/
private Bitmap downloadBitmap(String url) {
HttpURLConnection conn = null;
try {
conn = (HttpURLConnection) new URL(url).openConnection();
conn.setConnectTimeout(5000);
conn.setReadTimeout(5000);
conn.setRequestMethod("GET");
conn.connect();
int responseCode = conn.getResponseCode();
if (responseCode == 200) {
InputStream inputStream = conn.getInputStream();
//图片压缩处理
BitmapFactory.Options option = new BitmapFactory.Options();
option.inSampleSize = 2;//宽高都压缩为原来的二分之一, 此参数需要根据图片要展示的大小来确定
option.inPreferredConfig = Bitmap.Config.RGB_565;//设置图片格式
Bitmap bitmap = BitmapFactory.decodeStream(inputStream, null, option);
return bitmap;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
conn.disconnect();
}
return null;
}
}
// 从网络读
mNetCacheUtils.getBitmapFromNet(ivPic, url);
private MyBitmapUtils utils;
tils = new MyBitmapUtils();
utils.display(holder.ivPic, item.listimage);
35.本地缓存
(1)MD5算法
public class MD5Encoder {
public static String encode(String string) throws Exception {
byte[] hash = MessageDigest.getInstance("MD5").digest(
string.getBytes("UTF-8"));
StringBuilder hex = new StringBuilder(hash.length * 2);
for (byte b : hash) {
if ((b & 0xFF) < 0x10) {
hex.append("0");
}
hex.append(Integer.toHexString(b & 0xFF));
}
return hex.toString();
}
}
(2)本地缓存
/**
* 本地缓存
*
* @author Kevin
*
*/
public class LocalCacheUtils {
public static final String CACHE_PATH = Environment
.getExternalStorageDirectory().getAbsolutePath() + "/zhbj_cache_52";
/**
* 从本地sdcard读图片
*/
public Bitmap getBitmapFromLocal(String url) {
try {
String fileName = MD5Encoder.encode(url);
File file = new File(CACHE_PATH, fileName);
if (file.exists()) {
Bitmap bitmap = BitmapFactory.decodeStream(new FileInputStream(
file));
return bitmap;
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 向sdcard写图片
*
* @param url
* @param bitmap
*/
public void setBitmapToLocal(String url, Bitmap bitmap) {
try {
String fileName = MD5Encoder.encode(url);
File file = new File(CACHE_PATH, fileName);
File parentFile = file.getParentFile();
if (!parentFile.exists()) {// 如果文件夹不存在, 创建文件夹
parentFile.mkdirs();
}
// 将图片保存在本地
bitmap.compress(CompressFormat.JPEG, 100,
new FileOutputStream(file));
} catch (Exception e) {
e.printStackTrace();
}
}
}
36.内存缓存
(1)内存溢出OOM
(2)Android默认给每个app只分配16M的内存
(3)java中的引用
-强引用 垃圾回收器不会回收, java默认引用都是强引用
- 软引用 SoftReference 在内存不够时,垃圾回收器会考虑回收
- 弱引用 WeakReference 在内存不够时,垃圾回收器会优先回收
- 虚引用 PhantomReference 在内存不够时,垃圾回收器最优先回收
注意: Android2.3+, 系统会优先将SoftReference的对象提前回收掉, 即使内存够用
(4)内存溢出OOM解决方案
图片三级缓存之内存缓存 http://blog.youkuaiyun.com/fancylovejava/article/details/25705169
a.使用软引用代替强引用,见代码和视频---------------建议不用
b.LruCache
least recentlly use 最少最近使用算法
会将内存控制在一定的大小内, 超出最大值时会自动回收, 这个最大值开发者自己定
/**
* 内存缓存
*
* @author Kevin
*
*/
public class MemoryCacheUtils {
// private HashMap<String, SoftReference<Bitmap>> mMemoryCache = new
// HashMap<String, SoftReference<Bitmap>>(); 用软引用来代替强引用
private LruCache<String, Bitmap> mMemoryCache;
public MemoryCacheUtils() {
long maxMemory = Runtime.getRuntime().maxMemory() / 8;// 模拟器默认是16M
mMemoryCache = new LruCache<String, Bitmap>((int) maxMemory) {
@Override
protected int sizeOf(String key, Bitmap value) {
int byteCount = value.getRowBytes() * value.getHeight();// 获取图片占用内存大小
return byteCount;
}
};
}
/**
* 从内存读
*
* @param url
*/
public Bitmap getBitmapFromMemory(String url) {
// SoftReference<Bitmap> softReference = mMemoryCache.get(url);
// if (softReference != null) {
// Bitmap bitmap = softReference.get();
// return bitmap;
// }
return mMemoryCache.get(url);
}
/**
* 写内存
*
* @param url
* @param bitmap
*/
public void setBitmapToMemory(String url, Bitmap bitmap) {
// SoftReference<Bitmap> softReference = new
// SoftReference<Bitmap>(bitmap);
// mMemoryCache.put(url, softReference);
mMemoryCache.put(url, bitmap);
}
}
37.图片压缩
BitmapFactory.Options option = new BitmapFactory.Options();
option.inSampleSize = 2;//宽高都压缩为原来的二分之一, 此参数需要根据图片要展示的大小来确定
option.inPreferredConfig = Bitmap.Config.RGB_565;//设置图片格式
Bitmap bitmap = BitmapFactory.decodeStream(inputStream, null, option);
return bitmap;
38.内存溢出解决方案
(1)方案解决总结
(2)面试---------------见视频
39.极光推送
******见之前写的或看视频
40.屏幕适配
********见之前的或看视频