mainActivity如下:
package cn.ifeng.com; import java.util.ArrayList; import android.app.Activity; import android.os.Bundle; import android.os.Parcelable; import android.support.v4.view.PagerAdapter; import android.support.v4.view.ViewPager; import android.support.v4.view.ViewPager.OnPageChangeListener; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.ViewGroup.LayoutParams; import android.view.Window; import android.widget.ImageView; //笔记: //利用ViewPager来实现一个应用程序的欢迎界面 //0 比ViewPager使用示例(二)要优化一些 //1 布局较简单.包含两个东西:ViewPager和几个小圆点的集合 //2 初始化所有用于展示的图片和所有的小圆点 //3 给ViewPager添加适配器并且对其滑动实现监听 //4 参考资料 // http://malong26.iteye.com/blog/1332730 // http://blog.csdn.net/notice520/article/details/7454568 // http://blog.csdn.net/wangkuifeng0118/article/details/7388166 public class ViewPagerTestActivity extends Activity { private ViewPager viewPager; //ViewPager要显示的所有View private ArrayList<View> viewsList; private ViewGroup contentView,dotsGroup; //显示所有的小圆点 private ImageView [] dotImageViews; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); this.requestWindowFeature(Window.FEATURE_NO_TITLE); //初始化所有用于展示的图片 LayoutInflater inflater=this.getLayoutInflater(); viewsList=new ArrayList<View>(); ViewPageItemView view1 = new ViewPageItemView(this,R.drawable.guide01); viewsList.add(view1); ViewPageItemView view2 = new ViewPageItemView(this,R.drawable.guide02); viewsList.add(view2); ViewPageItemView view3 = new ViewPageItemView(this,R.drawable.guide03); viewsList.add(view3); ViewPageItemView view4 = new ViewPageItemView(this,R.drawable.guide04); viewsList.add(view4); ViewPageItemView view5 = new ViewPageItemView(this,R.drawable.guide05); viewsList.add(view5); dotImageViews=new ImageView[viewsList.size()]; contentView=(ViewGroup) inflater.inflate(R.layout.main, null); dotsGroup=(ViewGroup) contentView.findViewById(R.id.dotsGroup); viewPager=(ViewPager) contentView.findViewById(R.id.viewPager); //初始化所有的小圆点 for(int i=0;i<viewsList.size();i++){ ImageView imageView=new ImageView(ViewPagerTestActivity.this); //LayoutParams(10, 10)设置imageView的宽和高 imageView.setLayoutParams(new LayoutParams(10, 10)); //左,上,右,下的padding imageView.setPadding(10, 0, 10, 0); dotImageViews[i]=imageView; if(i==0){ // 默认进入程序后第一张图片被选中,所以第一个小圆点显示为亮白色 dotImageViews[i].setBackgroundResource(R.drawable.guide_dot_white); }else{ dotImageViews[i].setBackgroundResource(R.drawable.guide_dot_black); } //将每个点都存入dotsGroup中 dotsGroup.addView(dotImageViews[i]); } //初始化完成View列表和dotsGroup后才 setContentView() setContentView(contentView); viewPager.setAdapter(new MyPagerAdapter()); viewPager.setOnPageChangeListener(new MyOnPageChangeListener()); } //自定义适配器继承自PagerAdapter //当滑动时每次都会摧毁前一个界面,然后新建一个界面 class MyPagerAdapter extends PagerAdapter{ @Override public void startUpdate(View arg0) {} @Override public int getCount() { return viewsList.size(); } //初始化arg1位置的界面 @Override public Object instantiateItem(View arg0, int arg1) { ((ViewPager)arg0).addView(viewsList.get(arg1)); return viewsList.get(arg1); } //摧毁arg1位置的界面 @Override public void destroyItem(View arg0, int arg1, Object arg2) { ((ViewPager)arg0).removeView(viewsList.get(arg1)); } //判断是否由对象生成界面 @Override public boolean isViewFromObject(View arg0, Object arg1) { return arg0==arg1; } @Override public void finishUpdate(View arg0) {} @Override public void restoreState(Parcelable arg0, ClassLoader arg1) {} @Override public Parcelable saveState() {return null;} } //监听ViewPager实现图片滑动的过程 class MyOnPageChangeListener implements OnPageChangeListener{ //arg0==1的时候表示正在滑动,arg0==2的时候表示滑动完毕了 //arg0==0的时候表示什么都没做,就是停在那 @Override public void onPageScrollStateChanged(int arg0) {} //表示在前一个页面滑动到后一个页面的时候,在前一个页面滑动前调用的方法 @Override public void onPageScrolled(int arg0, float arg1, int arg2) {} //arg0是表示当前选中的页面,此方法是在页面跳转完毕的时候调用的 @Override public void onPageSelected(int arg0) { //滑动时改变小圆点的显示.循环很巧妙 for(int i=0;i<dotImageViews.length;i++){ //当前已经选中的. dotImageViews[arg0].setBackgroundResource(R.drawable.guide_dot_white); if(arg0!=i){ //当前未选中的. dotImageViews[i].setBackgroundResource(R.drawable.guide_dot_black); } } } } }
ViewPageItemView如下:
package cn.ifeng.com; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.widget.ImageView; import android.widget.RelativeLayout; import android.widget.Toast; public class ViewPageItemView extends RelativeLayout { private Context mContext; private ImageView mImageView; private RelativeLayout mLayout; private int mResoureId; public ViewPageItemView(Context context,int resoureId) { super(context); mContext=context; mResoureId=resoureId; init(); } private void init() { LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); mLayout = (RelativeLayout)inflater.inflate(R.layout.viewpage_item, null); addView(mLayout); mImageView = (ImageView)mLayout.findViewById(R.id.viewPage_item_imageView); mImageView.setImageResource(mResoureId); mImageView.setOnClickListener(new OnClickListener() { public void onClick(View v) { Toast.makeText(mContext, ""+mResoureId, Toast.LENGTH_SHORT).show(); } }); } }
main.xml如下:
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <android.support.v4.view.ViewPager android:id="@+id/viewPager" android:layout_width="fill_parent" android:layout_height="wrap_content" /> <RelativeLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="vertical" > <LinearLayout android:id="@+id/dotsGroup" android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_marginBottom="30dp" android:gravity="center_horizontal"> </LinearLayout> </RelativeLayout> </FrameLayout>
viewPager_item.xml如下:
<?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:orientation="vertical" > <ImageView android:id="@+id/viewPage_item_imageView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" /> </RelativeLayout>
快递物流行业:数据增量下载的实现 网络拓扑图
基础资料包括:操作人员信息,网点信息等,快递行业的网点人员,信息量过多,如果每次都采取全部下载的方式,会导致下载数据会等待很长一段时间,给用户体验带来不利的影响。
因此我们需要寻找一种增量下载的方式,来提高基础数据同步的效率。
下面就以操作人员的数据同步为例,给出相应的
数据库设计方案
ID
UserID
Name
CreateTime
UpdateTime
Enable
编号
用户名
姓名
数据创建时间
最近修改时间
是否启用
0: 停用
1:启用
1
0007
值守策
2012-10-24 20:11:36
2012-11-06 17:07:19
1
3
800107
库管测007
2012-10-24 18:01:17
2012-11-12 10:40:46
1
4
600202
雷网接2
2012-10-24 16:26:15
2012-11-06 17:52:46
1
5
88888888
fghfg
2012-11-08 11:36:14
2012-11-09 10:59:21
0
6
4002
押运2
2012-10-12 16:32:11
2012-11-07 11:02:17
1
WeService服务器(PC)端
思路:根据最近更新时间搜索最新的操作人员信息
WebService层代码: 业务逻辑层代码: 数据访问层代码: PDA(手持机)端
【思路:】
设手持机的最后一次更新时间为LastUpdateTime
1: 当 LastUpdateTime <UpdateTime 时,说明服务器上有最新的基础数据需要下载
手持机数据库设计:
操作人员表:和服务器端的设计结构大致相同
不同的是需要建立一个新表,设计一个字段即可
即:最近数据更新时间:LastUpdateTime日期型
获取最新的操作人员后,及时更新到PDA的本机数据库中
设计方案的优化
可以参考以下数据库的设计:
ID
UserID
Name
UpdateTime
OperFlag
编号
用户名
姓名
最近修改时间
操作类型标志
D(删除 delete,假删除)
U(更新 update)
I(新增 insert)
1
0007
值守策
2012-11-06 17:07:19
1
3
800107
库管测007
2012-11-12 10:40:46
1
4
600202
雷网接2
2012-11-06 17:52:46
1
5
88888888
fghfg
2012-11-09 10:59:21
0
6
4002
押运2
2012-11-07 11:02:17
1
【思路:】
设手持机的最后一次更新时间为LastUpdateTime
1: 当 LastUpdateTime <UpdateTime 时,说明服务器上有最新的基础数据需要下载
1)当OperFlag = D(假删除),客户机不需要执行下载的操作,只需要把对应的记录设置为D即可
2) 当OperFlag = U(修改),客户机需要执行下载的操作,可以采用数据覆盖的方式进行
3) 当OperFlag = I(新增), 客户机需要执行下载的操作,把服务器端的数量批量插入到客户机即可
这篇文章是专门用来记录开发中一些常见的BUG以及常用的零碎知识点,我会隔一段时间更新内容
最好不要在UIViewController的loadView方法中改变状态栏的可视性(比如状态栏由显示变为隐藏、或者由隐藏变为显示),因为会导致重复调用2次loadView和viewDidLoad方法
假设状态栏本来是处于显示状态的:
下面的是错误代码:
- (void)loadView { NSLog(@"loadView"); // 隐藏状态栏 [UIApplication sharedApplication].statusBarHidden = YES; // .... 创建UIView self.view = [[[UIView alloc] initWithFrame:[UIScreen mainScreen].bounds] autorelease]; self.view.backgroundColor = [UIColor grayColor]; } - (void)viewDidLoad { [super viewDidLoad]; NSLog(@"viewDidLoad"); }运行效果:
打印信息:
2013-02-26 00:51:36.152 weibo[2251:c07] loadView 2013-02-26 00:51:36.153 weibo[2251:c07] loadView 2013-02-26 00:51:36.153 weibo[2251:c07] viewDidLoad 2013-02-26 00:51:36.154 weibo[2251:c07] viewDidLoad
虽然运行效果是对的,但是系统连续调用了2次loadView和viewDidLoad方法,导致创建了2次UIView,造成了不必要的开销。
原因分析:
状态栏由显示变为隐藏,意味着屏幕的可用高度变长了,UIViewController的UIView的高度也要重新调整,因此系统会重新调用loadView方法创建UIView,创建完毕后再次调用viewDidLoad方法。
如果在UIImageView中添加了一个按钮,你会发现在默认情况下这个按钮是无法被点击的,需要设置UIImageView的userInteractionEnabled为YES:
imageView.userInteractionEnabled = YES;
设置为YES后,UIImageView内部的按钮就可以被点击了
原因分析:
• 当用户点击屏幕时,会产生一个触摸事件,系统会将该事件加入到一个由UIApplication管理的事件队列中
• UIApplication会从事件队列中取出最前面的事件进行分发以便处理,通常,先发送事件给应用程序的主窗口(UIWindow)
• 主窗口会调用hitTest:withEvent:方法在视图(UIView)层次结构中找到一个最合适的UIView来处理触摸事件
(hitTest:withEvent:其实是UIView的一个方法,UIWindow继承自UIView,因此主窗口UIWindow也是属于视图的一种)
•hitTest:withEvent:方法大致处理流程是这样的:
首先调用当前视图的pointInside:withEvent:方法判断触摸点是否在当前视图内:
▶ 若pointInside:withEvent:方法返回NO,说明触摸点不在当前视图内,则当前视图的hitTest:withEvent:返回nil
▶ 若pointInside:withEvent:方法返回YES,说明触摸点在当前视图内,则遍历当前视图的所有子视图(subviews),调用子视图的hitTest:withEvent:方法重复前面的步骤,子视图的遍历顺序是从top到bottom,即从subviews数组的末尾向前遍历,直到有子视图的hitTest:withEvent:方法返回非空对象或者全部子视图遍历完毕:
▷ 若第一次有子视图的hitTest:withEvent:方法返回非空对象,则当前视图的hitTest:withEvent:方法就返回此对象,处理结束
▷ 若所有子视图的hitTest:withEvent:方法都返回nil,则当前视图的hitTest:withEvent:方法返回当前视图自身(self)
• 最终,这个触摸事件交给主窗口的hitTest:withEvent:方法返回的视图对象去处理
我大致画了个iOS触摸事件分发的原理图:
• hitTest:withEvent:方法会忽略以下视图:
1> 隐藏(hidden=YES)的视图
2> 禁止用户操作(userInteractionEnabled=NO)的视图
3> alpha<0.01的视图
4> 如果一个子视图的区域超过父视图的区域(如果父视图的clipsToBounds属性为NO,超过父视图区域的子视图内容也会显示),那么正常情况下在父视图区域外的触摸操作不会被识别,因为父视图的pointInside:withEvent:方法会返回NO,这样就不会继续向下遍历子视图了。当然,也可以重写pointInside:withEvent:方法来处理这种
综上所述可得:如果父视图的userInteractionEnabled=NO,触摸事件不会继续往下传递给子视图,所以子视图永远无法处理触摸事件。而UIImageView在默认情况下的userInteractionEnabled就是NO。
由于iOS设备的屏幕分辨率不尽相同,有大有小,那么在不同设备中显示同一张图片,可能会造成图片被拉伸、变形,严重影响用户体验。为了让图片在不同设备中都能得到很好的显示效果,同一类图片我们一般会准备3种版本,比如iOS程序在启动时会全屏显示的Default.png图片:
(Retina即视网膜屏幕)
• Default.png(图片尺寸为320x480):显示在非Retina-3.5英寸屏幕上(iPhone3G\iPhone3GS,屏幕分辨率为320x480)
• Default@2x.png(图片尺寸为640x960):显示在Retina-3.5英寸屏幕上(iPhone4\iPhone4s,屏幕分辨为640x960)
• Default-568h@2x.png(图片尺寸为640x1136):显示在Retina-4.0英寸屏幕上(iPhone5,屏幕分辨率为640x1136)