[转载]android利用Bundle在activity间传递对象的方法 - - ITeye技术网站

mikel阅读(853)

[转载]利用Bundle在activity间传递对象的方法 – – ITeye技术网站.

假如需要在两个activity间传递数据,我们通常都是用Bundle,但是里面似乎只有一些放置一些Java中已经有的数据类型,像 String,int,double等,但如果要传递一个对象呢?不难发现Bundle中有一个方法putSerializable,利用该对象就可以传 递对象了,不过传递的对象要实现Serializable接口。例如要传递一个User对象,则示例代码如下:
User类

    public class User implements Serializable {  
        //其他代码省略  
    }  

activity中关键代码

    User user = new User();  
    Intent intent = new Intent(MyActivity.this,OthereActivity.class);  
    Bundle bundle = new Bundle();  
    bundle.putSerializable("user", user);  
    intent.putExtras(bundle);  
    startActivity(intent);  

[转载]Android Listview下拉刷新 上拉(滑动分页)加载更多 - 还是你最好 - 博客园

mikel阅读(1029)

[转载]listview下拉刷新 上拉(滑动分页)加载更多 – 还是你最好 – 博客园.

最 近做的类似于微博的项目中,有个Android功能要使用到listview的向下拉刷新来刷新最新消息,向上拉刷新(滑动分页)来加载更多。
新浪微博就是使用这种方式的典型。
当 用户从网络上读取微博的时候,如果一下子全部加载用户未读的微博这将耗费比较长的时间,造成不好的用户体验,同时一屏的内容也不足以显示如此多的内容。这 时候,我们就需要用到另一个功能,那就是listview的分页了,其实这个分页可以做成客户端的分页,也可以做成服务器端的分页(点击加载时,从服务器 对应的加载第N页就好了!!!)。通过分页分次加载数据,用户看多少就去加载多少。
通常这也分为两种方式,一种是设置一个按钮,用户点击即加载。另一种是当用户滑动到底部时自动加载。今天我就和大家分享一下滑动到底端时自动加载这个功能的实现。
效果图如下所示:

 

下拉刷新最主要的流程是:
(1). 下拉,显示提示头部界面(HeaderView),这个过程提示用户”下拉刷新”
(2). 下拉到一定程度,超出了刷新最基本的下拉界限,我们认为达到了刷新的条件,提示用户可以”松手刷新”了,效果上允许用户继续下拉
(3). 用户松手,可能用户下拉远远不止提示头部界面,所以这一步,先反弹回仅显示提示头部界面,然后提示用户”正在加载”。
(4). 加载完成后,隐藏提示头部界面。

那么让我们看看怎么才能实现呢???
第一步:既然是要显示listview ,那么就应该有个listview 的容器pulldown.xml

<!--?xml version="1.0" encoding="utf-8"?-->

第二步:自定义一个listview中显示的item对象pulldown_item.xml

<!--?xml version="1.0" encoding="utf-8"?-->

第三步:定义一个header的xml布局文件pulldown_header.xml

<!--?xml version="1.0" encoding="utf-8"?-->

&nbsp;

&nbsp;

&nbsp;

&nbsp;

&nbsp;

第四步:如果需要向上拉更新更多的话,那就定义一个底部的footer的布局文件,在此为方便起见,只定义一个progressbar跟textview,更加复杂的显示,就交给你们了~~~~~pulldown_footer.xml:

<!--?xml version="1.0" encoding="utf-8"?-->

&nbsp;

&nbsp;

第五步:那么主要的文件这才登场:::::::重写listview这个文件主要任务是提供触摸的事件的处理方法。

/**
*

一个可以监听ListView是否滚动到最顶部或最底部的自定义控件

* 只能监听由触摸产生的,如果是ListView本身Flying导致的,则不能监听
* 如果加以改进,可以实现监听scroll滚动的具体位置等
*/

public class ScrollOverListView extends ListView {

private int mLastY;
private int mTopPosition;
private int mBottomPosition;

public ScrollOverListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}

public ScrollOverListView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}

public ScrollOverListView(Context context) {
super(context);
init();
}

private void init(){
mTopPosition = 0;
mBottomPosition = 0;
}

@Override
public boolean onTouchEvent(MotionEvent ev) {
final int action = ev.getAction();
final int y = (int) ev.getRawY();

switch(action){
case MotionEvent.ACTION_DOWN:{
mLastY = y;
final boolean isHandled = mOnScrollOverListener.onMotionDown(ev);
if (isHandled) {
mLastY = y;
return isHandled;
}
break;
}

case MotionEvent.ACTION_MOVE:{
final int childCount = getChildCount();
if(childCount == 0) return super.onTouchEvent(ev);

final int itemCount = getAdapter().getCount() - mBottomPosition;

final int deltaY = y - mLastY;
//DLog.d("lastY=%d y=%d", mLastY, y);

final int firstTop = getChildAt(0).getTop();
final int listPadding = getListPaddingTop();

final int lastBottom = getChildAt(childCount - 1).getBottom();
final int end = getHeight() - getPaddingBottom();

final int firstVisiblePosition = getFirstVisiblePosition();

final boolean isHandleMotionMove = mOnScrollOverListener.onMotionMove(ev, deltaY);

if(isHandleMotionMove){
mLastY = y;
return true;
}

//DLog.d("firstVisiblePosition=%d firstTop=%d listPaddingTop=%d deltaY=%d", firstVisiblePosition, firstTop, listPadding, deltaY);
if (firstVisiblePosition &lt;= mTopPosition &amp;&amp; firstTop &gt;= listPadding &amp;&amp; deltaY &gt; 0) {
final boolean isHandleOnListViewTopAndPullDown;
isHandleOnListViewTopAndPullDown = mOnScrollOverListener.onListViewTopAndPullDown(deltaY);
if(isHandleOnListViewTopAndPullDown){
mLastY = y;
return true;
}
}

// DLog.d("lastBottom=%d end=%d deltaY=%d", lastBottom, end, deltaY);
if (firstVisiblePosition + childCount &gt;= itemCount &amp;&amp; lastBottom &lt;= end &amp;&amp; deltaY &lt; 0) {
final boolean isHandleOnListViewBottomAndPullDown;
isHandleOnListViewBottomAndPullDown = mOnScrollOverListener.onListViewBottomAndPullUp(deltaY);
if(isHandleOnListViewBottomAndPullDown){
mLastY = y;
return true;
}
}
break;
}

case MotionEvent.ACTION_UP:{
final boolean isHandlerMotionUp = mOnScrollOverListener.onMotionUp(ev);
if (isHandlerMotionUp) {
mLastY = y;
return true;
}
break;
}
}

mLastY = y;
return super.onTouchEvent(ev);
}

/**空的*/
private OnScrollOverListener mOnScrollOverListener = new OnScrollOverListener(){

@Override
public boolean onListViewTopAndPullDown(int delta) {
return false;
}

@Override
public boolean onListViewBottomAndPullUp(int delta) {
return false;
}

@Override
public boolean onMotionDown(MotionEvent ev) {
return false;
}

@Override
public boolean onMotionMove(MotionEvent ev, int delta) {
return false;
}

@Override
public boolean onMotionUp(MotionEvent ev) {
return false;
}

};

// =============================== public method ===============================

/**
* 可以自定义其中一个条目为头部,头部触发的事件将以这个为准,默认为第一个
*
* @param index 正数第几个,必须在条目数范围之内
*/
public void setTopPosition(int index){
if(getAdapter() == null)
throw new NullPointerException("You must set adapter before setTopPosition!");
if(index &lt; 0) throw new IllegalArgumentException("Top position must &gt; 0");

mTopPosition = index;
}

/**
* 可以自定义其中一个条目为尾部,尾部触发的事件将以这个为准,默认为最后一个
*
* @param index 倒数第几个,必须在条目数范围之内
*/
public void setBottomPosition(int index){
if(getAdapter() == null)
throw new NullPointerException("You must set adapter before setBottonPosition!");
if(index &lt; 0) throw new IllegalArgumentException("Bottom position must &gt; 0");

mBottomPosition = index;
}

/**
* 设置这个Listener可以监听是否到达顶端,或者是否到达低端等事件
*
* @see OnScrollOverListener
*/
public void setOnScrollOverListener(OnScrollOverListener onScrollOverListener){
mOnScrollOverListener = onScrollOverListener;
}

/**
* 滚动监听接口
* @see ScrollOverListView#setOnScrollOverListener(OnScrollOverListener)
*
*/
public interface OnScrollOverListener {

/**
* 到达最顶部触发
*
* @param delta 手指点击移动产生的偏移量
* @return
*/
boolean onListViewTopAndPullDown(int delta);

/**
* 到达最底部触发
*
* @param delta 手指点击移动产生的偏移量
* @return
*/
boolean onListViewBottomAndPullUp(int delta);

/**
* 手指触摸按下触发,相当于{@link MotionEvent#ACTION_DOWN}
*
* @return 返回true表示自己处理
* @see View#onTouchEvent(MotionEvent)
*/
boolean onMotionDown(MotionEvent ev);

/**
* 手指触摸移动触发,相当于{@link MotionEvent#ACTION_MOVE}
*
* @return 返回true表示自己处理
* @see View#onTouchEvent(MotionEvent)
*/
boolean onMotionMove(MotionEvent ev, int delta);

/**
* 手指触摸后提起触发,相当于{@link MotionEvent#ACTION_UP}
*
* @return 返回true表示自己处理
* @see View#onTouchEvent(MotionEvent)
*/
boolean onMotionUp(MotionEvent ev);

}

}

第六步:下拉刷新控件,真正实现下拉刷新的是这个控件,而上面的那个ScrollOverListView只是提供触摸的事件等

/**
* 下拉刷新控件
* 真正实现下拉刷新的是这个控件,
* ScrollOverListView只是提供触摸的事件等
*/
public class PullDownView extends LinearLayout implements OnScrollOverListener{
private static final String TAG = "PullDownView";

private static final int START_PULL_DEVIATION = 50; // 移动误差
private static final int AUTO_INCREMENTAL = 10; // 自增量,用于回弹

private static final int WHAT_DID_LOAD_DATA = 1; // Handler what 数据加载完毕
private static final int WHAT_ON_REFRESH = 2; // Handler what 刷新中
private static final int WHAT_DID_REFRESH = 3; // Handler what 已经刷新完
private static final int WHAT_SET_HEADER_HEIGHT = 4;// Handler what 设置高度
private static final int WHAT_DID_MORE = 5; // Handler what 已经获取完更多

private static final int DEFAULT_HEADER_VIEW_HEIGHT = 105; // 头部文件原本的高度

private static SimpleDateFormat dateFormat = new SimpleDateFormat("MM-dd HH:mm");

private View mHeaderView;
private LayoutParams mHeaderViewParams;
private TextView mHeaderViewDateView;
private TextView mHeaderTextView;
private ImageView mHeaderArrowView;
private View mHeaderLoadingView;
private View mFooterView;
private TextView mFooterTextView;
private View mFooterLoadingView;
private ScrollOverListView mListView;

private OnPullDownListener mOnPullDownListener;
private RotateAnimation mRotateOTo180Animation;
private RotateAnimation mRotate180To0Animation;

private int mHeaderIncremental; // 增量
private float mMotionDownLastY; // 按下时候的Y轴坐标

private boolean mIsDown; // 是否按下
private boolean mIsRefreshing; // 是否下拉刷新中
private boolean mIsFetchMoreing; // 是否获取更多中
private boolean mIsPullUpDone; // 是否回推完成
private boolean mEnableAutoFetchMore; // 是否允许自动获取更多

// 头部文件的状态
private static final int HEADER_VIEW_STATE_IDLE = 0; // 空闲
private static final int HEADER_VIEW_STATE_NOT_OVER_HEIGHT = 1; // 没有超过默认高度
private static final int HEADER_VIEW_STATE_OVER_HEIGHT = 2; // 超过默认高度
private int mHeaderViewState = HEADER_VIEW_STATE_IDLE;

public PullDownView(Context context, AttributeSet attrs) {
super(context, attrs);
initHeaderViewAndFooterViewAndListView(context);
}

public PullDownView(Context context) {
super(context);
initHeaderViewAndFooterViewAndListView(context);
}

/*
* ==================================
* Public method
* 外部使用,具体就是用这几个就可以了
*
* ==================================
*/

/**
* 刷新事件接口
*/
public interface OnPullDownListener {
void onRefresh();
void onMore();
}

/**
* 通知加载完了数据,要放在Adapter.notifyDataSetChanged后面
* 当你加载完数据的时候,调用这个notifyDidLoad()
* 才会隐藏头部,并初始化数据等
*/
public void notifyDidLoad() {
mUIHandler.sendEmptyMessage(WHAT_DID_LOAD_DATA);
}

/**
* 通知已经刷新完了,要放在Adapter.notifyDataSetChanged后面
* 当你执行完刷新任务之后,调用这个notifyDidRefresh()
* 才会隐藏掉头部文件等操作
*/
public void notifyDidRefresh() {
mUIHandler.sendEmptyMessage(WHAT_DID_REFRESH);
}

/**
* 通知已经获取完更多了,要放在Adapter.notifyDataSetChanged后面
* 当你执行完更多任务之后,调用这个notyfyDidMore()
* 才会隐藏加载圈等操作
*/
public void notifyDidMore() {
mUIHandler.sendEmptyMessage(WHAT_DID_MORE);
}

/**
* 设置监听器
* @param listener
*/
public void setOnPullDownListener(OnPullDownListener listener){
mOnPullDownListener = listener;
}

/**
* 获取内嵌的listview
* @return ScrollOverListView
*/
public ListView getListView(){
return mListView;
}

/**
* 是否开启自动获取更多
* 自动获取更多,将会隐藏footer,并在到达底部的时候自动刷新
* @param index 倒数第几个触发
*/
public void enableAutoFetchMore(boolean enable, int index){
if(enable){
mListView.setBottomPosition(index);
mFooterLoadingView.setVisibility(View.VISIBLE);
}else{
mFooterTextView.setText("更多");
mFooterLoadingView.setVisibility(View.GONE);
}
mEnableAutoFetchMore = enable;
}

/*
* ==================================
* Private method
* 具体实现下拉刷新等操作
*
* ==================================
*/

/**
* 初始化界面
*/
private void initHeaderViewAndFooterViewAndListView(Context context){
setOrientation(LinearLayout.VERTICAL);
//setDrawingCacheEnabled(false);
/*
* 自定义头部文件
* 放在这里是因为考虑到很多界面都需要使用
* 如果要修改,和它相关的设置都要更改
*/
mHeaderView = LayoutInflater.from(context).inflate(R.layout.pulldown_header, null);
mHeaderViewParams = new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
addView(mHeaderView, 0, mHeaderViewParams);

mHeaderTextView = (TextView) mHeaderView.findViewById(R.id.pulldown_header_text);
mHeaderArrowView = (ImageView) mHeaderView.findViewById(R.id.pulldown_header_arrow);
mHeaderLoadingView = mHeaderView.findViewById(R.id.pulldown_header_loading);

// 注意,图片旋转之后,再执行旋转,坐标会重新开始计算
mRotateOTo180Animation = new RotateAnimation(0, 180,
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);
mRotateOTo180Animation.setDuration(250);
mRotateOTo180Animation.setFillAfter(true);

mRotate180To0Animation = new RotateAnimation(180, 0,
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);
mRotate180To0Animation.setDuration(250);
mRotate180To0Animation.setFillAfter(true);

/**
* 自定义脚部文件
*/
mFooterView = LayoutInflater.from(context).inflate(R.layout.pulldown_footer, null);
mFooterTextView = (TextView) mFooterView.findViewById(R.id.pulldown_footer_text);
mFooterLoadingView = mFooterView.findViewById(R.id.pulldown_footer_loading);
mFooterView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if(!mIsFetchMoreing){
mIsFetchMoreing = true;
mFooterLoadingView.setVisibility(View.VISIBLE);
mOnPullDownListener.onMore();
}
}
});

/*
* ScrollOverListView 同样是考虑到都是使用,所以放在这里
* 同时因为,需要它的监听事件
*/
mListView = new ScrollOverListView(context);
mListView.setOnScrollOverListener(this);
mListView.setCacheColorHint(0);
addView(mListView, LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);

// 空的listener
mOnPullDownListener = new OnPullDownListener() {
@Override
public void onRefresh() {}
@Override
public void onMore() {}
};
}

/**
* 在下拉和回推的时候检查头部文件的状态
* 如果超过了默认高度,就显示松开可以刷新,
* 否则显示下拉可以刷新
*/
private void checkHeaderViewState(){
if(mHeaderViewParams.height &gt;= DEFAULT_HEADER_VIEW_HEIGHT){
if(mHeaderViewState == HEADER_VIEW_STATE_OVER_HEIGHT) return;
mHeaderViewState = HEADER_VIEW_STATE_OVER_HEIGHT;
mHeaderTextView.setText("松开可以刷新");
mHeaderArrowView.startAnimation(mRotateOTo180Animation);
}else{
if(mHeaderViewState == HEADER_VIEW_STATE_NOT_OVER_HEIGHT
|| mHeaderViewState == HEADER_VIEW_STATE_IDLE) return;
mHeaderViewState = HEADER_VIEW_STATE_NOT_OVER_HEIGHT;
mHeaderTextView.setText("下拉可以刷新");
mHeaderArrowView.startAnimation(mRotate180To0Animation);
}
}

private void setHeaderHeight(final int height){
mHeaderIncremental = height;
mHeaderViewParams.height = height;
mHeaderView.setLayoutParams(mHeaderViewParams);
}

/**
* 自动隐藏动画
*/
class HideHeaderViewTask extends TimerTask{
@Override
public void run() {
if(mIsDown) {
cancel();
return;
}
mHeaderIncremental -= AUTO_INCREMENTAL;
if(mHeaderIncremental &gt; 0){
mUIHandler.sendEmptyMessage(WHAT_SET_HEADER_HEIGHT);
}else{
mHeaderIncremental = 0;
mUIHandler.sendEmptyMessage(WHAT_SET_HEADER_HEIGHT);
cancel();
}
}
}

/**
* 自动显示动画
*/
class ShowHeaderViewTask extends TimerTask{

@Override
public void run() {
if(mIsDown) {
cancel();
return;
}
mHeaderIncremental -= AUTO_INCREMENTAL;
if(mHeaderIncremental &gt; DEFAULT_HEADER_VIEW_HEIGHT){
mUIHandler.sendEmptyMessage(WHAT_SET_HEADER_HEIGHT);
}else{
mHeaderIncremental = DEFAULT_HEADER_VIEW_HEIGHT;
mUIHandler.sendEmptyMessage(WHAT_SET_HEADER_HEIGHT);
if(!mIsRefreshing){
mIsRefreshing = true;
mUIHandler.sendEmptyMessage(WHAT_ON_REFRESH);
}
cancel();
}
}
}

private Handler mUIHandler = new Handler(){

@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case WHAT_DID_LOAD_DATA:{
mHeaderViewParams.height = 0;
mHeaderLoadingView.setVisibility(View.GONE);
mHeaderTextView.setText("下拉可以刷新");
mHeaderViewDateView = (TextView) mHeaderView.findViewById(R.id.pulldown_header_date);
mHeaderViewDateView.setVisibility(View.VISIBLE);
mHeaderViewDateView.setText("更新于:" + dateFormat.format(new Date(System.currentTimeMillis())));
mHeaderArrowView.setVisibility(View.VISIBLE);
showFooterView();
return;
}

case WHAT_ON_REFRESH:{
// 要清除掉动画,否则无法隐藏
mHeaderArrowView.clearAnimation();
mHeaderArrowView.setVisibility(View.INVISIBLE);
mHeaderLoadingView.setVisibility(View.VISIBLE);
mOnPullDownListener.onRefresh();
return;
}

case WHAT_DID_REFRESH :{
mIsRefreshing = false;
mHeaderViewState = HEADER_VIEW_STATE_IDLE;
mHeaderArrowView.setVisibility(View.VISIBLE);
mHeaderLoadingView.setVisibility(View.GONE);
mHeaderViewDateView.setText("更新于:" + dateFormat.format(new Date(System.currentTimeMillis())));
setHeaderHeight(0);
showFooterView();
return;
}

case WHAT_SET_HEADER_HEIGHT :{
setHeaderHeight(mHeaderIncremental);
return;
}

case WHAT_DID_MORE :{
mIsFetchMoreing = false;
mFooterTextView.setText("更多");
mFooterLoadingView.setVisibility(View.GONE);
}
}
}

};

/**
* 显示脚步脚部文件
*/
private void showFooterView(){
if(mListView.getFooterViewsCount() == 0 &amp;&amp; isFillScreenItem()){
mListView.addFooterView(mFooterView);
mListView.setAdapter(mListView.getAdapter());
}
}

/**
* 条目是否填满整个屏幕
*/
private boolean isFillScreenItem(){
final int firstVisiblePosition = mListView.getFirstVisiblePosition();
final int lastVisiblePostion = mListView.getLastVisiblePosition() - mListView.getFooterViewsCount();
final int visibleItemCount = lastVisiblePostion - firstVisiblePosition + 1;
final int totalItemCount = mListView.getCount() - mListView.getFooterViewsCount();

if(visibleItemCount &lt; totalItemCount) return true; return false; } /* * ================================== * 实现 OnScrollOverListener接口 * * * ================================== */ @Override public boolean onListViewTopAndPullDown(int delta) { if(mIsRefreshing || mListView.getCount() - mListView.getFooterViewsCount() == 0) return false; int absDelta = Math.abs(delta); final int i = (int) Math.ceil((double)absDelta / 2); mHeaderIncremental += i; if(mHeaderIncremental &gt;= 0){ // &amp;&amp; mIncremental &lt;= mMaxHeight
setHeaderHeight(mHeaderIncremental);
checkHeaderViewState();
}
return true;
}

@Override
public boolean onListViewBottomAndPullUp(int delta) {
if(!mEnableAutoFetchMore || mIsFetchMoreing) return false;
// 数量充满屏幕才触发
if(isFillScreenItem()){
mIsFetchMoreing = true;
mFooterTextView.setText("加载更多中...");
mFooterLoadingView.setVisibility(View.VISIBLE);
mOnPullDownListener.onMore();
return true;
}
return false;
}

@Override
public boolean onMotionDown(MotionEvent ev) {
mIsDown = true;
mIsPullUpDone = false;
mMotionDownLastY = ev.getRawY();
return false;
}

@Override
public boolean onMotionMove(MotionEvent ev, int delta) {
//当头部文件回推消失的时候,不允许滚动
if(mIsPullUpDone) return true;

// 如果开始按下到滑动距离不超过误差值,则不滑动
final int absMotionY = (int) Math.abs(ev.getRawY() - mMotionDownLastY);
if(absMotionY &lt; START_PULL_DEVIATION) return true; final int absDelta = Math.abs(delta); final int i = (int) Math.ceil((double)absDelta / 2); // onTopDown在顶部,并上回推和onTopUp相对 if(mHeaderViewParams.height &gt; 0 &amp;&amp; delta &lt; 0){ mHeaderIncremental -= i; if(mHeaderIncremental &gt; 0){
setHeaderHeight(mHeaderIncremental);
checkHeaderViewState();
}else{
mHeaderViewState = HEADER_VIEW_STATE_IDLE;
mHeaderIncremental = 0;
setHeaderHeight(mHeaderIncremental);
mIsPullUpDone = true;
}
return true;
}
return false;
}

@Override
public boolean onMotionUp(MotionEvent ev) {
mIsDown = false;
// 避免和点击事件冲突
if(mHeaderViewParams.height &gt; 0){
// 判断头文件拉动的距离与设定的高度,小了就隐藏,多了就固定高度
int x = mHeaderIncremental - DEFAULT_HEADER_VIEW_HEIGHT;
Timer timer = new Timer(true);
if(x &lt; 0){
timer.scheduleAtFixedRate(new HideHeaderViewTask(), 0, 10);
}else{
timer.scheduleAtFixedRate(new ShowHeaderViewTask(), 0, 10);
}
return true;
}
return false;
}

}

第七步:这个java文件就是封装数据,然后调用上两个文件就好了。废话不多说,上代码:::::

public class PullDownActivity extends Activity implements OnPullDownListener, OnItemClickListener{

private static final int WHAT_DID_LOAD_DATA = 0;
private static final int WHAT_DID_REFRESH = 1;
private static final int WHAT_DID_MORE = 2;

private ListView mListView;
private ArrayAdapter mAdapter;

private PullDownView mPullDownView;
private List mStrings = new ArrayList();

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.pulldown);

/*
* 1.使用PullDownView
* 2.设置OnPullDownListener
* 3.从mPullDownView里面获取ListView
*/
mPullDownView = (PullDownView) findViewById(R.id.pull_down_view);
mPullDownView.setOnPullDownListener(this);
mListView = mPullDownView.getListView();

mListView.setOnItemClickListener(this);
mAdapter = new ArrayAdapter(this, R.layout.pulldown_item, mStrings);
mListView.setAdapter(mAdapter);

mPullDownView.enableAutoFetchMore(true, 1);

loadData();
}

private void loadData(){
new Thread(new Runnable() {

@Override
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
List strings = new ArrayList();
for (String body : mStringArray) {
strings.add(body);
}
Message msg = mUIHandler.obtainMessage(WHAT_DID_LOAD_DATA);
msg.obj = strings;
msg.sendToTarget();
}
}).start();
}

@Override
public void onRefresh() {
new Thread(new Runnable() {

@Override
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Message msg = mUIHandler.obtainMessage(WHAT_DID_REFRESH);
msg.obj = "After refresh " + System.currentTimeMillis();
msg.sendToTarget();
}
}).start();
}

@Override
public void onMore() {
new Thread(new Runnable() {

@Override
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Message msg = mUIHandler.obtainMessage(WHAT_DID_MORE);
msg.obj = "After more " + System.currentTimeMillis();
msg.sendToTarget();
}
}).start();
}

private Handler mUIHandler = new Handler(){

@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case WHAT_DID_LOAD_DATA:{
if(msg.obj != null){
List strings = (List) msg.obj;
if(!strings.isEmpty()){
mStrings.addAll(strings);
mAdapter.notifyDataSetChanged();
}
}
// 诉它数据加载完毕;
mPullDownView.notifyDidLoad();
break;
}
case WHAT_DID_REFRESH :{
String body = (String) msg.obj;
mStrings.add(0, body);
mAdapter.notifyDataSetChanged();
// 告诉它更新完毕
mPullDownView.notifyDidRefresh();
break;
}

case WHAT_DID_MORE:{
String body = (String) msg.obj;
mStrings.add(body);
mAdapter.notifyDataSetChanged();
// 告诉它获取更多完毕
mPullDownView.notifyDidMore();
break;
}
}

}

};

@Override
public void onItemClick(AdapterView&lt;?&gt; parent, View view, int position, long id) {
Toast.makeText(this, "啊,你点中我了 " + position, Toast.LENGTH_SHORT).show();
}

// 模拟数据
private String[] mStringArray = {
"Abbaye de Belloc", "Abbaye du Mont des Cats", "Abertam", "Abondance", "Ackawi",
"Acorn", "Adelost", "Affidelice au Chablis", "Afuega'l Pitu", "Airag", "Airedale",
"Aisy Cendre", "Allgauer Emmentaler", "Alverca", "Ambert", "American Cheese"
};

}

整个程序就这么完成了,总之,可以使用前两个封装好的文件,然后,调用就好了~~~~没什么太难的地方。

 

源代码下载地址:我是传送门   我也是个传送门

http://k-beta.com/android-listview-more-refresh.html

[转载]android开源框架android-async-http使用 - OPEN 开发经验库

mikel阅读(759)

[转载]android开源框架android-async-http使用 – OPEN 开发经验库.

Android-async-http开源框架可以是我们轻松的获取网络数据或者向服务器发送数据,使用起来也很简单,下面做简单介绍,具体详细使用看官网:https://github.com/loopj/android-async-http

1.新建项目,去官网下载zip包,解压,打开releases文件,把里面最新的jar包,考入项目工程libs目录下,引入包。

2.通过1,就可以使用了,很简单,下面是自己写的demo,用它提供的各种不同方法完成从服务器获取一个json数据:

package com.http;
import com.loopj.android.http.AsyncHttpClient;
import com.loopj.android.http.AsyncHttpResponseHandler;
import com.loopj.android.http.BinaryHttpResponseHandler;
import com.loopj.android.http.JsonHttpResponseHandler;
import com.loopj.android.http.RequestParams;

public class HttpUtil {
    private static     AsyncHttpClient client =new AsyncHttpClient();    //实例话对象
    static
    {
        client.setTimeout(11000);   //设置链接超时,如果不设置,默认为10s
    }
    public static void get(String urlString,AsyncHttpResponseHandler res)    //用一个完整url获取一个string对象
    {
        client.get(urlString, res);
    }
    public static void get(String urlString,RequestParams params,AsyncHttpResponseHandler res)   //url里面带参数
    {
        client.get(urlString, params,res);
    }
    public static void get(String urlString,JsonHttpResponseHandler res)   //不带参数,获取json对象或者数组
    {
        client.get(urlString, res);
    }
    public static void get(String urlString,RequestParams params,JsonHttpResponseHandler res)   //带参数,获取json对象或者数组
    {
        client.get(urlString, params,res);
    }
    public static void get(String uString, BinaryHttpResponseHandler bHandler)   //下载数据使用,会返回byte数据
    {
        client.get(uString, bHandler);
    }
    public static AsyncHttpClient getClient()
    {
        return client;
    }
}

这个类主要列出了我们常用的get方法,在要使用的地方,调用该类就行了。

具体使用的类:

package com.http;

import java.io.File;
import java.io.FileOutputStream;

import org.json.JSONArray;
import org.json.JSONObject;

import android.app.Activity;
import android.app.ProgressDialog;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;

import com.loopj.android.http.AsyncHttpResponseHandler;
import com.loopj.android.http.BinaryHttpResponseHandler;
import com.loopj.android.http.JsonHttpResponseHandler;
import com.loopj.android.http.RequestParams;

public class MainActivity extends Activity {
    private TextView textView; // 顶部textview
    private ProgressDialog pDialog;
    private TextView textView2; // 下面textview,显示获取的所有数据
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textView = (TextView) findViewById(R.id.text);
        textView2 = (TextView) findViewById(R.id.text2);
    }
    public void method1(View view) {
        pDialog = ProgressDialog.show(this, "请稍等", "数据加载中");
        String urlString = "http://client.azrj.cn/json/cook/cook_list.jsp?type=1&p=2&size=10"; // 一個獲取菜谱的url地址
        HttpUtil.get(urlString, new AsyncHttpResponseHandler() {
            public void onSuccess(String arg0) { // 获取数据成功会调用这里
                pDialog.dismiss();
                textView.setText("获取json数据成功,看下面");
                textView2.setText(arg0);
                Log.i("hck", arg0);
            };
            public void onFailure(Throwable arg0) { // 失败,调用
                Toast.makeText(MainActivity.this, "onFailure",
                        Toast.LENGTH_LONG).show();
            };
            public void onFinish() { // 完成后调用,失败,成功,都要掉
            };
        });
    }
    public void method2(View view) {
        String urlString = "http://client.azrj.cn/json/cook/cook_list.jsp?";
        RequestParams params = new RequestParams(); // 绑定参数
        params.put("type", "1");
        params.put("p", "2");
        params.put("size", "10");
        HttpUtil.get(urlString, params, new JsonHttpResponseHandler() {
            public void onSuccess(JSONArray arg0) { // 成功后返回一个JSONArray数据
                Log.i("hck", arg0.length() + "");
                try {
                    textView.setText("菜谱名字:"
                            + arg0.getJSONObject(2).getString("name")); //返回的是JSONArray, 获取JSONArray数据里面的第2个JSONObject对象,然后获取名字为name的数据值
                } catch (Exception e) {
                    Log.e("hck", e.toString());
                }
            };
            public void onFailure(Throwable arg0) {
                Log.e("hck", " onFailure" + arg0.toString());
            };
            public void onFinish() {
                Log.i("hck", "onFinish");
            };
            public void onSuccess(JSONObject arg0) {   //返回的是JSONObject,会调用这里
                Log.i("hck", "onSuccess ");
                try {
                    textView.setText("菜谱名字:"
                            + arg0.getJSONArray("list").getJSONObject(0)
                                    .getString("name"));
                } catch (Exception e) {
                    Log.e("hck", e.toString());
                }
            };
        });
    }
    public void method3(View view) {
        String urlString = "http://client.azrj.cn/json/cook/cook_list.jsp?type=1&p=2&size=10";
        HttpUtil.get(urlString, new JsonHttpResponseHandler() {
            public void onSuccess(JSONObject arg0) {
                try {
                    textView.setText("菜谱名字:"
                            + arg0.getJSONArray("list").getJSONObject(1)
                                    .getString("name"));
                } catch (Exception e) {
                    Log.e("hck", e.toString());
                }
            };
        });
    }
    public void method4(View view) {
        String urlString = "http://client.azrj.cn/json/cook/cook_list.jsp?";
        final RequestParams params = new RequestParams();
        params.put("type", "1");
        params.put("p", "2");
        params.put("size", "10");
        HttpUtil.get(urlString, params, new AsyncHttpResponseHandler() {
            public void onSuccess(String arg0) {
                try {
                    JSONObject jObject = new JSONObject(arg0);
                    textView.setText("菜谱名字:"
                            + jObject.getJSONArray("list").getJSONObject(2)
                                    .getString("name"));
                    Log.i("hck", params.getEntity().toString());
                } catch (Exception e) {
                }
            };
        });
    }
    public void method5(View view) {
        String url = "http://f.hiphotos.baidu.com/album/w%3D2048/sign=38c43ff7902397ddd6799f046dbab3b7/9c16fdfaaf51f3dee973bf7495eef01f3b2979d8.jpg";
        HttpUtil.get(url, new BinaryHttpResponseHandler() {
            @Override
            public void onSuccess(byte[] arg0) {
                super.onSuccess(arg0);
                File file = Environment.getExternalStorageDirectory();
                File file2 = new File(file, "cat");
                file2.mkdir();
                file2 = new File(file2, "cat.jpg");
                try {
                    FileOutputStream oStream = new FileOutputStream(file2);
                    oStream.write(arg0);
                    oStream.flush();
                    oStream.close();
                    textView.setText("可爱的猫咪已经保存在sdcard里面");
                } catch (Exception e) {
                    e.printStackTrace();
                    Log.i("hck", e.toString());
                }
            }
        });
    }
}

布局文件:

<ScrollView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
      android:gravity="center_horizontal"
    >
    <LinearLayout
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical"
      android:gravity="center_horizontal">
    <TextView
        android:textColor="#FF0000"
        android:textSize="16sp"
       android:layout_marginTop="20dp"
     android:gravity="center_horizontal"
        android:id="@+id/text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="获取数据完成后会显示在这里" />
<Button
    android:layout_marginTop="50dp"
    android:id="@+id/bt1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="第一种"
    android:onClick="method1"
    />
<Button
    android:id="@+id/bt2"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="第2种"
    android:onClick="method2"
    />
<Button
    android:id="@+id/bt3"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="第3种"
      android:onClick="method3"
    />
<Button
    android:id="@+id/bt4"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="第4种"
      android:onClick="method4"
    />
<Button
    android:id="@+id/bt5"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="第5种"
      android:onClick="method5"
    />
  <TextView
        android:textColor="#FF0000"
        android:textSize="16sp"
       android:layout_marginTop="20dp"
     android:gravity="center_horizontal"
        android:id="@+id/text2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
         />
</LinearLayout>
</ScrollView>

很简单很实用,上面只是get方法的,上传数据,和这个也差不多,大家自己建个服务器,试试。

[转载]Cocos2d-x 版本小游戏 《是男人就下100层》 项目开源 - jeekun - 博客园

mikel阅读(846)

[转载]Cocos2d-x 版本小游戏 《是男人就下100层》 项目开源 – jeekun – 博客园.

这个是很久就开始动手写的一个小游戏了,直到最近才把它收尾了,拖拖拉拉的毛病总是很难改啊。

项目是基于 cocos2d-x v2.2 版本 ,目前只编译到了 Win8 平台上,并且已经上传到了商店,支持 ARM 以及 X86,其它平台的可以自己动手术去编译。

下载试玩:点这里 

 

项目介绍

这毕竟是个小游戏,本身其实没有什么技术难点,主要在于项目的设计,分为如下几个小模块

 

1、玩家 (Player)

玩家类我用了单例模式,继承自CCSprite,因为贯穿游戏一直会有玩家存在,在这个版本里也不会有第二个,所以单例成了我很好的选择。

封装了 运动、血量 等。整体的游戏运动采取了背景运动而人不动的方式,感觉在这里这种要更容易掌控一些,分层很明显。

 

2、平台 

这里我参照了 Floyd 的Js版本实现,以 BlockBase 作为所有平台游戏的基类,实现了向上运动,检测玩家碰撞,移除平台等基础功能。

然后根据不同的平台类型,继承该基类实现不同效果,比如跳起,伤害,左右平移等。

分别有:NormalBlock (最普通的平台) 、FlipBlock(让人弹跳的平台)、MissBlock(会破损的平台)、ThornBlock(带刺的平台)、LeftRunBlock、RightRunBlock (左右运动的平台)

还有个 BlockFactory 工厂类, 负责在恰当的时候创建合适的平台,创建的规则是随机类型,位置是从预先定义的几个里面随机取。

对于所有平台的管理, 本来最好应该是做个缓存池的,但是我发现这个性能降低实在是可以忽略,所以。。。

 

3、输入

输入这里,定义了一个基类,InputBase,因为最终肯定有几种输入的方式:PC(键盘、鼠标)、手势、重力感应等,所以这个从一开始就要考虑到。具体的处理方式是 给定一个固定的运动速度,

然后有输入事件的时候就让玩家按照这个速度来运行, 但是现在实际的效果感觉还不太理想。

 

4、场景

场景就是那么基础的几个了。。。游戏主界面采用了MVC的模式来设计,CCScene 作为 Controller ,其它的Layer 作为View。其它页面都比较简单,单Layer 实现。逻辑也都放在Layer里了。

另外,专门定义了一个 HideLayer ,目的是实现弹出对话框的效果,考虑到原场景中可能会有CCMenu,我将该 Layer 的 优先级设为了 与 CCMenu 相同,因为后添加的原因,所以总能屏蔽

Menu 的事件, 而且在 Layer 上再添加Menu 也不会有问题。 

还有个比较有意思的是: 所有的场景我都继承了 IBackableScene 接口,这是我自己定义的一个抽象类,因为我发现对于 “后退” 按钮的处理在游戏中是非常常见的,所以这个接口里定义了

bool GoBack() = 0 函数, 所有需要响应后退事件的场景都要实现该方法,然后在该方法里实现具体的返回 代码。

 

 

大致的就是这些了,具体的有兴趣的可以来看源码。

Github地址:https://github.com/jeekun/DownFloors

 

参考游戏:

http://www.cnblogs.com/floyd/archive/2010/11/03/1868323.html

资源来源:

http://www.4399.com/flash/1164_1.htm

 

 

 

欢迎有兴趣的童鞋加入Cocos2d-x 开发群  qq: 264152376

[转载]Mac OS X安装之虚拟机环境下的总结 - Hey_Chris - 博客园

mikel阅读(961)

[转载]Mac OS X安装之虚拟机环境下的总结 – Hey_Chris – 博客园.

最近一直忙着公司iOS Touch的新版发布,终于忙过了。现在,又开始了新的阶段,不过算是轻松了很多。回来一看,自己的博客空空如也,实在受不了了。于是,开始更一下吧,哈哈。

这个文档是我几个月前,开始配置苹果虚拟机时候,记录的资料,现在拿出,一方面是为了开始记录自己的学习和开发心得,另一方面也给刚开始学习iOS开发的朋友提供一点参考,如有不足,望指正^_^

图片是从我的空间链接的,如果无法看到,请链接到这里:http://user.qzone.qq.com/370381830/2

 

正文:

一周以来,我都在摸索Mac OS X操作系统在非苹果机上的安装,由于是公司的组装机,存在与苹果操作系统的兼容性问题,而且一开始经理建议在硬盘上安装操作系统,所以折腾了一周多的时间。期间采用了硬盘引导安装,光盘引导安装,虚拟机安装等方法。

其中的苦痛无以言表,重启电脑几百次,刻盘、分区、格式化、引导,等待超级慢网速下载资源···只是在成功进入系统界面的那一刻,我感觉心里突然亮 了起来,温暖的感觉充满全身,每个细胞都活跃了起来。我却没有想象中的欢呼雀跃,淡定是我唯一的表情,仿佛感受到了微风拂过,带来一缕清香···

至此,安装工作顺利完成了,Xcode开发环境也已经配置好。

为了保存资料和总结安装经验,便写下这篇文档。顶原创呀!

 

这篇文档主要讲的是在虚拟机环境下的Mac OS X成功安装经验。

安装准备:

  1. 组装机操作系统为64位Windows 7旗舰版。
  2. 虚拟机为VMware Workstation 9。

(百度网盘下载:http://pan.baidu.com/share/link?shareid=130040&uk=2181393914

  1. VMware Workstation破解安装Mac OS补丁:unlock-all 110

(下载地址:VMware-workstation-full MAC补丁.rar

  1. BIOS支持硬件虚拟化(Hardware Virtualization)和硬件数据执行保护(Hardware DEP),并且都为开启状态,务必首先开启,血的教训!

(需要开机进入BIOS设置为Enable状态)

  1. 目标操作系统为Mac OS X 10.8.3的cdr安装文件。也可选择其他格式安装文件,例如dmg或者iso格式镜像。貌似有的版本安装会失败,我尝试过大概四个版本的安装程序,这个版本成功了。

(迅雷快传下载:http://kuai.xunlei.com/d/QtkbAgLesgBQgkZR787

  1. VMware Tools工具,实现虚拟机的增强效果,例如全屏无黑边和鼠标在宿主机和虚拟机界面的自由移动。(下载地址:苹果Mac OS VMware Tools Darwin.rar

 

开始安装:

  1. 安装虚拟机
  2. 安装破解补丁

等待批处理文件自动运行完毕。

 

3.      配置虚拟机

新建一个虚拟机

图片

选择用户自定义模式

图片

图片

图片

 

选择操作系统的时候,需要选择Apple Mac OS X。前提是必须先安装破解补丁。版本要选择与所安装的操作系统版本符合,这里为64位,故如下选择。

 


图片

 

填入虚拟机名称和安装路径。


图片

根据自己的需要选择
cpu配置,分别为处理器个数和每个处理器的核数。
图片

由于选择了64位操作系统,故内存至少为4G
图片

网络连接选择了桥接模式,由于公司内部采用ipmac地址绑定的方式,故需要手动设置虚拟机IPv4地址。若为家庭网络,可选择NAT模式。
图片

最大硬盘容量不低于推荐值。
图片

图片

图片

创建好虚拟机后,进入设置。

图片

可将软驱删除(remove)。可能会因为软驱导致异常问题。
图片

进入硬盘的高级设置(Advanced)。
图片

选择(0:8)。
图片

然后在光驱设置里,选择“Use ISO image file”,浏览时候选择所有文件类型,因为我采用的是cdr格式安装文件。
图片

设置完以后,启动虚拟机,进入安装界面。
图片

选择安装语言。
图片

需要磁盘工具。
图片

将分配好的磁盘抹掉,格式为“
Mac OS 扩展(日志式)”,类似于Windows下的格式化。

图片

图片

此处因为我的磁盘里已经安装好操作系统,便没有抹掉,若抹掉以后,就会在此处看到磁盘,选择安装即可。
图片

此后便是等待安装完成。

重启后进入苹果操作系统。

 

安装后话:

1.      网络配置

进入虚拟网络设置
图片

添加网络VMnet0,并选择桥接到本地以太网网卡。
图片

点击“系统偏好设置”,选择网络,可以进入“高级”中设置ipdns
图片

图片

设置完成。

 

2.      VMware Tools

右键右下角的光盘图标,选择设置。

图片

文件选择
VMware Tools的镜像文件。

图片

加载后,在桌面上双击安装。

图片

 

 

3.      与宿主机共享文件夹

图片

在“选项”中选择“Shared Folders”,设置为“Always enabled”。并“Add”一个新文件夹路径,最后确定。

图片

前往Windows的对应路径,可以找到共享文件夹。此内的文件都实现宿主机和虚拟机共享。
图片

         到此,用虚拟机安装的过程总结就结束了,其他方式请查看后续文档,总算没有白费力,老朽深感欣慰呀···

[转载]Mac OS X安装之硬盘和光盘引导总结 - Hey_Chris - 博客园

mikel阅读(971)

[转载]Mac OS X安装之硬盘和光盘引导总结 – Hey_Chris – 博客园.

继上一篇虚拟机环境下的安装,这篇文档主要描述硬盘和光盘引导安装Mac OS X,并可实现多操作系统。

硬盘安装:

首先介绍下硬盘安装需要用到的软件。

  1. Java虚拟机。作为HFSExplorer的运行前提环境。
  2. HFSExplorer。这款软件用来剥离dmg、cdr格式的OS X的安装程序的引导层。
  3. HD Install Helper。其实就是Leopard硬盘安装助手。用来将HFSExplorer生成的操作系统镜像文件写入自己分配好的硬盘引导区域。
  4. MacDrive。该软件可让Windows用户查看苹果的HFS+磁盘的文件。
  5. DGFree。也就是DiskGenius。用来查看和管理磁盘的工具,例如查看磁盘信息详细、格式化磁盘、修改分区标示符、修改盘符等。
  6. Mach_kernel和mbr替换文件。用于破解正式版安装程序的内核文件。
  7. HJMac。用于引导启动多系统选择界面。
  8. EasyBCD。加载和设置多系统选择项。

 

好了,了解这些软件以后,在安装之前,还有一些准备要做。

  1. 在BIOS中开启硬盘AHIC模式和硬件DPE(数据保护执行)
  2. 尽量下载懒人版的操作系统,避免繁琐的成功率低的内核破解
  3. 做好安装失败的心理准备,毕竟操作系统与硬件的兼容问题很麻烦,耐心折腾吧

 

接下来就可以开始安装步骤了。

  1. 准备硬盘分区。

点击“开始”,搜索“list disk”,确定,出现磁盘管理界面

右键有空余空间的磁盘,最好可用空间大于30G。我这里选择D盘。

选择压缩卷。

输入压缩空间量3000MB(约30G)。(说明:这个空间量根据操作系统来分配。比如分配30G空间,操作系统为6G,那么假设用一个7G的空间来放操作系统的引导程序,则有23G空间来正式的安装操作系统。具体分配根据自己的需要。)

 

再将分出来的压缩卷,新建简单卷

特别注意这一步,不要格式化。而且在后面的提示也不要格式化。

同样的步骤,将剩余的空间也新建简单卷。结果如下:

2. 接下来剥离操作系统镜像的引导层。

安装并打开HFSExplorer。前提是安装了Java虚拟机。选择Load file system from file

我这里是选择操作系统dmg镜像文件。(还有cdr格式的镜像文件也可以)

确定以后,Tools—>Create disk image。确定后,等待生成磁盘引导用dmg文件。

3. 将dmg镜像写入系统引导磁盘分区

运行Leopard硬盘安装助手,打开刚生成的镜像文件,并选择目标分区(我这里是分配好的约7G的E盘)。注意去掉三个已勾选项。等待进度条读完(可能出现假死状态,请耐心等待)。

按照我的经历来说,出现上面的成功画面很难得。多数时候是“Change partition type to AF:Failed”。不过没有关系,系统文件应该是写入了对应分区,只是没有将分区的标识符改为AF(AF为OS X磁盘的标识符)。如果出现这情况,那需要手动按照如下方式修改:

也可以用到前面提到的DiskGenius工具软件修改,或者进行其他操作。

4. 查看HFS格式磁盘

在Windows下,是无法直接查看HFS格式的磁盘的,因为刚才写入操作系统时候,已经将7G的分区改为了HFS格式。所以需要借助McDrive来查看。我这里是McDrive Pro 9,安装好先。应该可以看到如下情况:

如果需要破解内核,可以直接找到对应目录文件进行文件覆盖。在此不多介绍。

5. 准备多系统引导工作

将下载好的HJMac镜像文件直接放在非Windows系统盘的根目录下,我直接放在d盘下。

 

运行EasyBCD,选择“Add New Entry”,选择ISO Boot,输入Name,然后选择HJMac.iso文件,最后“Add Entry”。

6. 可以重启电脑了,然后选择“Mac OS X”,进入操作系统的安装。

 

到此,硬盘的引导安装完成了,后面的安装过程与在虚拟机上的步骤一样。不过需要注意,这种安装方式存在驱动与硬件不兼容的问题,所以如何选择合适的驱动需要折腾很久,不断的重启电脑是家常便饭。

同样会遇到其他问题,例如操作系统镜像有问题,BIOS里的设置不正确等等。但是基本的步骤就是这样,当然,引导程序也可以用变色龙或者BootThink之类的,只有自己多尝试了。

最后推荐几篇文章,希望对安装有帮助。

http://bbs.pcbeta.com/viewthread-592288-1-2.html

http://blog.csdn.net/momo2010programer/article/details/6098874

 

 

光盘安装:

这种方式算是最简单的方式了。

你需要做的事情,就是将硬盘安装步骤中,生成的磁盘引导安装dmg镜像,用刻录软件刻成系统安装盘,然后用光驱引导即可。

这个过程中,也会遇到很多兼容性问题,毕竟直接在组装机上安装,难度比较大。

那么,接下来的工作便需要各位在自己的pc机上不断尝试了。

[转载]浏览器批量打印条码纸 - 郑某 - 博客园

mikel阅读(1349)

[转载]浏览器批量打印条码纸 – 郑某 – 博客园.

前两天遇到了一个需要浏览器打印条码的需求,因为目前的管理系统是基于B/S的,在生产管理员用户那里需要将订单转为生产指令单,与此同时需要将订单中的产品批量打印出来条码纸来,以便生产完毕后贴到产品上面方便扫码入库和标注产品。

 先从打印机开始

    提供给我的是一台科诚打印机G500,实际使用效果还不错。目前很多的条码打印机厂商提供了可视化的条码打印软件,可以直接打印出来条码,还可以生成相应的EZPL指令,方便开发者使用指令来开发条码打印,当然还提供了基础的二次开发包和文档。

   下图是科诚官网下载的GO-LABLE打印设计软件。

使 用非常简单,摆弄一会儿就明白怎么玩了,这款打印软件提供了基础的条码图形,文字和图像图形工具,拖动到设计界面即可,这里需要注意的是,在使用字体的时 候有两种可以选择,一种是打印机内建字体,一种是windows字体,如果你条码上的文字不需要改变了,那就建议使用windows字体,这样打印出来的 文字清晰度很高,如果文字需要动态改变,比如我遇到的这个需求,那么就必须使用内建字体了,双击条码上的文字,会出现文字设定:

这里我选择了亚洲字体,使用前需要先下载亚洲字体到打印机,其实就是把本机的中文字体下载到打印机。其他的文字来源我试过了,但是只有这个选项可以打印出来中文而不出现乱码。

设计完成后,我们可以输出指令到右面的命令视窗,多观察一下,你会发现其实这就是按照一定的规则生产的一串配置信息,告诉打印机纸张的大小信息,要 出现一个什么样的图像,什么文本的文字,文字的字体类型,以及所有的这些元素的位置坐标信息,有了这些信息,打印机便可以按照要求输出打印图像了。我们可 以试着改变命令窗口的信息,然后输入回到设计界面,你就会发现设计效果已经按照你的修改发生了改变。

大家可能已经发现了,我在所有需要动态更改的地方,用@+相应的字段表示,目的就是为了以此为模板,通过替换模版的元素达到动态输出的效果。

这里着重讲一下二维码配置信息

W30,22,5,2,M,8,10,5,0
@单号

其中“@单号”是二维码的文本信息,上面配置信息倒数第二个,也就是那个“5”,是二维码信息的长度,,一个中文是两个字节,所以“@单号”的长度就是5了,如果文本信息换成其他的了,这里的“5”,也要做相应的改变。

制作ActiveX控件

如 果是做成winform,程序,那应该说是非常的简单了,直接调用提供的dll就行了,可现在要求在浏览器中完成这个任务,浏览器想调用dll,那就得用 的ActiveX控件了。关于ActiveX控件的开发和安装部署,网上有一些教程,其实和做winform差不多,只是添加一下guid,修改一下控件 属性就行了,真的是非常方便。下面把核心代码贴出来

//Trace.dll是官方提供的,放到bin文件夹下面<br>[DllImport("Trace.dll")]
        public static extern void sendcommand(
            [MarshalAs(UnmanagedType.LPArray)]
            byte[] command);
 public void printdata(string danhao,string kehu,string guige,string houdu,string yanse,string kuandu,string gaodu,string pingmi)
        {<br>            //获取程序集的文件夹目录,也就是安装后控件程序集所在的目录
            string sApplicationPath = Assembly.GetExecutingAssembly().Location;<br>//找到Data.cmd,这里是命令窗口中生成的那些指令信息,放到bin文件下,安装程序会把控件的dll和这个Data.cmd一起打包输出,这里就要求安装程//序务必吧Data.cmd包含进去。如果是调试状态,程序或到obj/debug文件下寻找Data.cmd,所以为了调试不出错,也放到那里一份Data.cmd
            sApplicationPath = sApplicationPath.Replace("CodexPrint.dll","Data.cmd");          
            using (StreamReader sr = new StreamReader(sApplicationPath, Encoding.GetEncoding("GB2312")))
            {
                StringBuilder sb = new StringBuilder();
                string sLine = "";
                while (sLine != null)
                {
                    sLine = sr.ReadLine();
                    if (sLine != null && !sLine.Equals(""))
                    {<br>                        //特别要注意必须每次读一行后添加上换行符,否则待会还原成字节数组的时候发给打印机,打印机不懂你在讲什么
                        sLine += Environment.NewLine;
                        sb.Append(sLine);
                    }
                }
                sr.Close();<br>                //去除空的部分
                string temp = sb.ToString().Trim();
 
                //获取单号的字节长度,替换"@单号"的长度5,一个汉字两个长度
                string erweimapeizhixinxi=temp.Substring(temp.IndexOf("W30"),(temp.LastIndexOf("@单号") -temp.IndexOf("W30") -1));
                string[] arraytemp=erweimapeizhixinxi.Split(new char[]{','});
                arraytemp[arraytemp.Length - 2] = Encoding.GetEncoding("GB2312").GetBytes(danhao ).Length.ToString();
                temp = temp.Replace(erweimapeizhixinxi,string.Join(",",arraytemp));
 
                //开始替换数据
                temp = temp.Replace("@单号", danhao);
                temp = temp.Replace("@客户", kehu);
                temp = temp.Replace("@规格", guige);
                temp = temp.Replace("@厚度", houdu);
                temp = temp.Replace("@颜色", yanse);
                temp = temp.Replace("@宽度", kuandu);
                temp = temp.Replace("@高度", gaodu);
                temp = temp.Replace("@平米", pingmi);
                
                byte[] buffer = Encoding.GetEncoding("GB2312").GetBytes(temp);
                openport("6"); //Ex:USB
                try
                {
                    sendcommand(buffer);
                    closeport();
                }
                catch (Exception error)
                {
                    MessageBox.Show(error.Message);
                    return;
                }
            }
        }

这样ActiveX控件的开发就基本完成了,然后就可以在PC安装了,类似工行网站在使用之前必须安装控件一样。

页面使用

ActiveX控件安装完毕后,页面的使用就简单了


在startprint方法里,我们可以通过js来调用控件中的printdata方法了。这里我循环了表格中的数据,然后逐行打印

<script type="text/javascript">
     function startprint() {
         var p = document.getElementById("BarCodePrint");
         var tableObj = document.getElementById("data");
         for (var i = 1; i < tableObj.rows.length; i++) {
             var rowcells = tableObj.rows[i].cells;
             var jsondata = { "danhao": rowcells[0].innerHTML, "kehu": rowcells[11].innerHTML, "guige": rowcells[1].innerHTML + rowcells[2].innerHTML,
                 "yanse": rowcells[3].innerHTML, "houdu": rowcells[4].innerHTML, "kuandu": rowcells[5].innerHTML, "gaodu": rowcells[6].innerHTML,
                 "pingmi": rowcells[10].innerHTML
             };
            //也可以省去定义json的过程,直接将数据传入下面的方法
            p.printdata(jsondata.danhao, jsondata.kehu, jsondata.guige, jsondata.houdu, jsondata.yanse, jsondata.kuandu, jsondata.gaodu, jsondata.pingmi);           
         }
                     
     }      
     
    </script>

这样整个工作就完成了,实测效果良好。ActiveX控件只能在IE下使用,谷歌浏览器还得使用其他插件配合,不过作为生产环节上的一环,要求工作人员使用IE就行了,呵呵。如果有一天突然想改变标签上的布局了,那么在GO-LABLE中重新设计好后生成新的指令,找到ActiveX控件的安装目录,找到Data.cmd,替换掉原来的的指令就可以了。但是这里面的模版替换元素必须形式一样,而且不能增加新的字段,如果增加的话,那就得重新开发升级ActiveX控件了。其实还有更灵活的方法,比如只传入方法一个字符串,里面包含了需要替换的标签和标签数据,通过分隔符区分,比如“@单号:0000001|@颜色:红色|………”,然后进行字符串处理就行了。当然页面的调用形式也相应做出改变就行。

[转载]Android应用空间之列表视图(ListView)介绍-Android开发-最全的Android开发资料-eoe移动开发者社区

mikel阅读(908)

[转载]Android应用空间之列表视图(ListView)介绍-Android开发-最全的Android开发资料-eoe移动开发者社区.

http://docs.eoeandroid.com/guide/topics/ui/layout/listview.html

作者:smilysas

更新时间:2012年7月28日

列表视图是一个成列显示滚动项的视图组合。成列的项都通过Adapter]被自动插入到列表中,其中,Adapter适配器可以从数组或者数据库查询中提取出内容并转化成列表视图中的项。

%E6%96%87%E4%BB%B6:Listview.png

* 使用一个加载者*

使用一个CursorLoader是避免一个异步任务查询光标Cursor时阻塞程序主线程的标准途径。当CursorLoader收到一个Cursor结果,LoaderCallbacks会收到一个对onLoadFinished()的回调,这时可以利用新的Cursor和列表视图更新Adapter并显示结果。

虽然CursorLoader函数在Android3.0(API级别 11)中才第一次引入,程序可以通过引入Support Library使用它们来支持运行Android 1.6及以上的设备。

要查看更多关于利用Loader异步加载数据的信息,请参看Loaders

* 例子:*

下面的例子是把ListView作为唯一默认布局元素的活动ListActivity。它完成向Contacts Provider查询姓名和电话号码清单的功能。

为了使用CursorLoader向列表动态加载数据,这个活动实现了LoaderCallbacks接口。

public class ListViewLoader extends ListActivity
implements LoaderManager.LoaderCallbacks {
// This is the Adapter being used to display the list's data
SimpleCursorAdapter mAdapter;

// These are the Contacts rows that we will retrieve
static final String[] PROJECTION = new String[] {ContactsContract.Data._ID,
        ContactsContract.Data.DISPLAY_NAME};

// This is the select criteria
static final String SELECTION = "((" + 
        ContactsContract.Data.DISPLAY_NAME + " NOTNULL) AND (" +
        ContactsContract.Data.DISPLAY_NAME + " != '' ))";

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // Create a progress bar to display while the list loads
    ProgressBar progressBar = new ProgressBar(this);
    progressBar.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
            LayoutParams.WRAP_CONTENT, Gravity.CENTER));
    progressBar.setIndeterminate(true);
    getListView().setEmptyView(progressBar);

    // Must add the progress bar to the root of the layout
    ViewGroup root = (ViewGroup) findViewById(android.R.id.content);
    root.addView(progressBar);

    // For the cursor adapter, specify which columns go into which views
    String[] fromColumns = {ContactsContract.Data.DISPLAY_NAME};
    int[] toViews = {android.R.id.text1}; // The TextView in simple_list_item_1

    // Create an empty adapter we will use to display the loaded data.
    // We pass null for the cursor, then update it in onLoadFinished()
    mAdapter = new SimpleCursorAdapter(this, 
            android.R.layout.simple_list_item_1, null,
            fromColumns, toViews, 0);
    setListAdapter(mAdapter);

    // Prepare the loader.  Either re-connect with an existing one,
    // or start a new one.
    getLoaderManager().initLoader(0, null, this);
}

// Called when a new Loader needs to be created
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
    // Now create and return a CursorLoader that will take care of
    // creating a Cursor for the data being displayed.
    return new CursorLoader(this, ContactsContract.Data.CONTENT_URI,
            PROJECTION, SELECTION, null, null);
}

// Called when a previously created loader has finished loading
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
    // Swap the new cursor in.  (The framework will take care of closing the
    // old cursor once we return.)
    mAdapter.swapCursor(data);
}

// Called when a previously created loader is reset, making the data unavailable
public void onLoaderReset(Loader<Cursor> loader) {
    // This is called when the last Cursor provided to onLoadFinished()
    // above is about to be closed.  We need to make sure we are no
    // longer using it.
    mAdapter.swapCursor(null);
}

@Override 
public void onListItemClick(ListView l, View v, int position, long id) {
    // Do something when a list item is clicked
}

注意* :因为这个例子要向Contacts Provider请求查询数据,程序需要在制作清单文件中请求READ_CONTACTS权限:

[转载]史上最全系列之用户界面之progressbar-Android开发资料下载-eoe Android开发者社区_Android开发论坛

mikel阅读(895)

[转载]史上最全系列之用户界面之progressbar-Android开发资料下载-eoe Android开发者社区_Android开发论坛.

前言
Android程序中,经常有一些操作需要用户等待一段时间,才能完成用户指定的任务,例如,发送短信,下载网络上的文 件等。如果在等待过程中不给用户一个程序还在“活着”,还在执行操作的提示的话,用户可能会以为程序卡死而强制结束程序。ProgressBar,顾名思 义,就是一个进度条,它可以提醒用户操作还在执行,执行了多少。灵活运用ProgressBar,对提升用户体验有很大的帮助。
我这里会带领大家做一个简单的程序,这里用了多线程在后台执行操作,并实现了Progressbar最常用了两种用法,希望对刚刚接触Android开发的朋友有一些帮助。

ProgressBar简介

在Adnroid中,系统提供的ProgressBar主要有两种样式。

第一种Indeterminate模式,也是默认的一种:

就是一个小圈圈在那转圈。
第二种,就是传统意义上的进度条。

第一种一般做为一个不需要让用户知道操作完成度,或者无法知道操作完成度时,仅仅用作一个提示器来告诉用户操作仍在进行, 第二种则可以设置进度,让用户看到操作进行了多少,大概还需要等待多久。两种方式各有其用途,至于用哪一个就要看场景了。你也可以自定义 ProgressBar的样式。

你需要注意,Progressbar仅仅是一个指示器,操作是需要在后台进行的。你的Progressbar的进度要尽量 准确的反应后台操作的进度。当Progressbar进度显示为完成的话,你要确保你的的程序的后台操作已经完成。不然的话,容易给用户一些错误的心理预 期,当预期与事实不符合的时候,用户可能会有受到欺骗的感觉。

ProgressBar重要方法概述

setMax(int):设置Progressbar进度的最大值
setProgress(int):设置当前进度
getMax():返回这个进度条的范围的上限

getProgress():返回进度

getSecondaryProgress():返回次要进度

incrementProgressBy(int diff):指定增加的进度

isIndeterminate():指示进度条是否在不确定模式下

setIndeterminate(boolean indeterminate):设置不确定模式下

setVisibility(int v):设置该进度条是否可视

代码讲解
程序最终界面:

右上角那个刷新图标,目前还不是Progressbar,仅仅是一个图片,运行起来的话会替换成一个圆圈式的progressbar。开始按钮下方的长条就是一个进度式progressbar。
程序功能就是点击开始按钮,条式progressbar每秒前进10%,10秒完成,于此同时右上角progressbar也一直转动。

首先布局文件

<!--?xml version="1.0" encoding="utf-8"?-->

/&gt;
<button>
</button>

主程序代码:

package com.example.eoeprogressbar;

import android.app.ActionBar;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.TextView;

public class EOEProgressbar extends Activity{
EditText edit_url;
Button btn_open;
TextView text_msg;
ActionBar actionBar;
ProgressBar progressBar;
Menu mOptionsMenu=null;
private View mRefreshIndeterminateProgressView = null;
String Url;
boolean refreshing=false;

private Handler handler=new Handler(){
@Override
public void handleMessage(Message msg){
int m=(Integer)msg.obj;
progressBar.setProgress(m);
if(m==10){
refreshing=!refreshing;
setRefreshActionItemState(refreshing);
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_eoeprogressbar);
FindView();
progressBar.setMax(10);
progressBar.setProgress(0);
btn_open.setOnClickListener(new View.OnClickListener() {

@Override
public void onClick(View v) {
// TODO Auto-generated method stub
if(!refreshing){

new Thread(){
public void run(){
for(int i=0;i&lt;10;i++){
postMsg(i+1);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
} .start();
refreshing=!refreshing;
setRefreshActionItemState(refreshing);
}

}
});
}

private void postMsg(Integer value){
Message message=Message.obtain();
message.obj=value;
handler.sendMessage(message);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.eoeprogressbar, menu);
mOptionsMenu=menu;
return true;
}

private void FindView(){
actionBar=getActionBar();
btn_open=(Button)findViewById(R.id.open);
text_msg=(TextView)findViewById(R.id.message);
progressBar=(ProgressBar)findViewById(R.id.progress);
}

public void setRefreshActionItemState(boolean refreshing) {
// On Honeycomb, we can set the state of the refresh button by giving it a custom
// action view.
if (mOptionsMenu == null) {
return;
}
final MenuItem refreshItem = mOptionsMenu.findItem(R.id.action_refresh);
if (refreshItem != null) {
if (refreshing) {
if (mRefreshIndeterminateProgressView == null) {
LayoutInflater inflater = (LayoutInflater)
EOEProgressbar.this.getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
mRefreshIndeterminateProgressView = inflater.inflate(
R.layout.actionbar_indeterminate_progress, null);
}

refreshItem.setActionView(mRefreshIndeterminateProgressView);
} else {
refreshItem.setActionView(null);
}
}
}

}

从程序运行逻辑开始一步一步讲解。
设置进度条最大进度为10,当前进度为0:
代码片段,双击复制
01
02

progressBar.setMax(10);
progressBar.setProgress(0);

开始按钮的点击事件:

btn_open.setOnClickListener(new View.OnClickListener() {

@Override
public void onClick(View v) {
// TODO Auto-generated method stub
if(!refreshing){

new Thread(){
public void run(){
for(int i=0;i&lt;10;i++){
postMsg(i+1);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
} .start();
refreshing=!refreshing;
setRefreshActionItemState(refreshing);
}

}
});

refreshing自定义的boolen型变量,用来判断工作状态。操作必须用多线程操作,不然无法实时更新界面。

new Thread(){
public void run(){
for(int i=0;i&lt;10;i++){
postMsg(i+1);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
} .start();

这里就是另开一个线程,在这个线程里执行一个循环,执行十次,每次休眠1秒。
postMsg是像handler发送消息的方法,代码如下:

private void postMsg(Integer value){
Message message=Message.obtain();
message.obj=value;
handler.sendMessage(message);
}

功能就是像handler发送进度。

setRefreshActionItemState是将右上角刷新选项替换成一个圆圈式progressbar的方法。这个代码是我从google的simlple中找到的,写的很不错。大家可一多看看。

private Handler handler=new Handler(){
@Override
public void handleMessage(Message msg){
int m=(Integer)msg.obj;
progressBar.setProgress(m);
if(m==10){
refreshing=false;
setRefreshActionItemState(refreshing);
}
}
};

这里是handler接受消息后处理的过程。通过progressBar.setProgress(m)来设置progressbar 的进度。当m=10时,则操作完成,移除上方圆圈式progressbar。

程序中用到了条式进度条显示操作完成状态,圆圈式进度条显示操作正在进行,基本progressbar的常用操作就是这两种了。
最后给大家点参考资料,有空可以去看看。
花样Android ProgressBar 史上最强大讲解http://www.eoeandroid.com/thread-1081-1-1.html
google官方文档:http://developer.Android.com/reference/Android/widget/ProgressBar.html
EOEProgressBar.zip (1.19 MB, 下载次数: 81)
附件里有两个多余的java文件,忘了删除,大家请无视。

[转载]Android ListView中getView的原理+如何在ListView中放置多个item - 木乃猫 - 博客园

mikel阅读(872)

[转载][Android] ListView中getView的原理+如何在ListView中放置多个item – 木乃猫 – 博客园.

ListView 和 Adapter 的基础

工作原理:

  1. ListView 针对List中每个item,要求 adapter “给我一个视图” (getView)。
  2. 一个新的视图被返回并显示

如果我们有上亿个项目要显示怎么办?为每个项目创建一个新视图?NO!这不可能!

实际上Android为你缓存了视图。

Android中有个叫做Recycler的构件,下图是他的工作原理:

  1. 如果你有10亿个项目(item),其中只有可见的项目存在内存中,其他的在Recycler中。
  2. ListView先请求一个type1视图(getView)然后请求其他可见的项目。convertView在getView中是空(null)的。
  3. 当item1滚出屏幕,并且一个新的项目从屏幕低端上来时,ListView再请求一个type1视图。convertView此时不是空值了,它的值是item1。你只需设定新的数据然后返回convertView,不必重新创建一个视图。

请看下面的示例代码,这里在getView中使用了System.out进行输出

public class MultipleItemsList extends ListActivity {

private MyCustomAdapter mAdapter;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mAdapter = new MyCustomAdapter();
for (int i = 0; i &lt; 50; i++) {
mAdapter.addItem("item " + i);
}
setListAdapter(mAdapter);
}

private class MyCustomAdapter extends BaseAdapter {

private ArrayList mData = new ArrayList();
private LayoutInflater mInflater;

public MyCustomAdapter() {
mInflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}

public void addItem(final String item) {
mData.add(item);
notifyDataSetChanged();
}

@Override
public int getCount() {
return mData.size();
}

@Override
public String getItem(int position) {
return mData.get(position);
}

@Override
public long getItemId(int position) {
return position;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
System.out.println("getView " + position + " " + convertView);
ViewHolder holder = null;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.item1, null);
holder = new ViewHolder();
holder.textView = (TextView)convertView.findViewById(R.id.text);
convertView.setTag(holder);
} else {
holder = (ViewHolder)convertView.getTag();
}
holder.textView.setText(mData.get(position));
return convertView;
}

}

public static class ViewHolder {
public TextView textView;
}
}

执行程序,然后在Logcat中查看日志

 

getView 被调用 9 次 ,convertView 对于所有的可见项目是空值(如下)

 

02-05 13:47:32.559: INFO/System.out(947): getView 0 null
02-05 13:47:32.570: INFO/System.out(947): getView 1 null
02-05 13:47:32.589: INFO/System.out(947): getView 2 null
02-05 13:47:32.599: INFO/System.out(947): getView 3 null
02-05 13:47:32.619: INFO/System.out(947): getView 4 null
02-05 13:47:32.629: INFO/System.out(947): getView 5 null
02-05 13:47:32.708: INFO/System.out(947): getView 6 null
02-05 13:47:32.719: INFO/System.out(947): getView 7 null
02-05 13:47:32.729: INFO/System.out(947): getView 8 null

 

然后稍微向下滚动List,直到item10出现:

 

convertView仍然是空值,因为recycler中没有视图(item1的边缘仍然可见,在顶端)

 

02-05 13:48:25.169: INFO/System.out(947): getView 9 null

 

再滚动List

 

convertView不是空值了!item1离开屏幕到Recycler中去了,然后item11被创建

 

02-05 13:48:42.879: INFO/System.out(947): getView 10 android.widget.LinearLayout@437430f8

 

再滚动:

02-05 14:01:31.069: INFO/System.out(947): getView 11 android.widget.LinearLayout@437447d0
02-05 14:01:31.142: INFO/System.out(947): getView 12 android.widget.LinearLayout@43744ff8
02-05 14:01:31.279: INFO/System.out(947): getView 13 android.widget.LinearLayout@43743fa8
02-05 14:01:31.350: INFO/System.out(947): getView 14 android.widget.LinearLayout@43745820
02-05 14:01:31.429: INFO/System.out(947): getView 15 android.widget.LinearLayout@43746048
02-05 14:01:31.550: INFO/System.out(947): getView 16 android.widget.LinearLayout@43746870
02-05 14:01:31.669: INFO/System.out(947): getView 17 android.widget.LinearLayout@43747098
02-05 14:01:31.839: INFO/System.out(947): getView 18 android.widget.LinearLayout@437478c0
02-05 14:03:30.900: INFO/System.out(947): getView 19 android.widget.LinearLayout@43748df0
02-05 14:03:32.069: INFO/System.out(947): getView 20 android.widget.LinearLayout@437430f8

convertView 如我们所期待的非空了,在item11离开屏幕之后,它的视图(@437430f8)作为convertView容纳item21了

不同的项目布局(item layout)

我们再举一个稍微复杂的例子,在上例的list中加入一些分隔线

你需要做这些:

  1. 重(@Override)写 getViewTypeCount() – 返回你有多少个不同的布局
  2. 重写 getItemViewType(int) – 由position返回view type id
  3. 根据view item的类型,在getView中创建正确的convertView

以下是代码:

public class MultipleItemsList extends ListActivity {

private MyCustomAdapter mAdapter;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mAdapter = new MyCustomAdapter();
for (int i = 1; i &lt; 50; i++) {
mAdapter.addItem("item " + i);
if (i % 4 == 0) {
mAdapter.addSeparatorItem("separator " + i);
}
}
setListAdapter(mAdapter);
}

private class MyCustomAdapter extends BaseAdapter {

private static final int TYPE_ITEM = 0;
private static final int TYPE_SEPARATOR = 1;
private static final int TYPE_MAX_COUNT = TYPE_SEPARATOR + 1;

private ArrayList mData = new ArrayList();
private LayoutInflater mInflater;

private TreeSet mSeparatorsSet = new TreeSet();

public MyCustomAdapter() {
mInflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}

public void addItem(final String item) {
mData.add(item);
notifyDataSetChanged();
}

public void addSeparatorItem(final String item) {
mData.add(item);
// save separator position
mSeparatorsSet.add(mData.size() - 1);
notifyDataSetChanged();
}

@Override
public int getItemViewType(int position) {
return mSeparatorsSet.contains(position) ? TYPE_SEPARATOR : TYPE_ITEM;
}

@Override
public int getViewTypeCount() {
return TYPE_MAX_COUNT;
}

@Override
public int getCount() {
return mData.size();
}

@Override
public String getItem(int position) {
return mData.get(position);
}

@Override
public long getItemId(int position) {
return position;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
int type = getItemViewType(position);
System.out.println("getView " + position + " " + convertView + " type = " + type);
if (convertView == null) {
holder = new ViewHolder();
switch (type) {
case TYPE_ITEM:
convertView = mInflater.inflate(R.layout.item1, null);
holder.textView = (TextView)convertView.findViewById(R.id.text);
break;
case TYPE_SEPARATOR:
convertView = mInflater.inflate(R.layout.item2, null);
holder.textView = (TextView)convertView.findViewById(R.id.textSeparator);
break;
}
convertView.setTag(holder);
} else {
holder = (ViewHolder)convertView.getTag();
}
holder.textView.setText(mData.get(position));
return convertView;
}

}

public static class ViewHolder {
public TextView textView;
}
}

运行程序,你会看到每4个item一个分割线

看看日志,无异常,所有的convertView都是空的

 

02-05 15:19:03.080: INFO/System.out(1035): getView 0 null type = 0
02-05 15:19:03.112: INFO/System.out(1035): getView 1 null type = 0
02-05 15:19:03.130: INFO/System.out(1035): getView 2 null type = 0
02-05 15:19:03.141: INFO/System.out(1035): getView 3 null type = 0
02-05 15:19:03.160: INFO/System.out(1035): getView 4 null type = 1
02-05 15:19:03.170: INFO/System.out(1035): getView 5 null type = 0
02-05 15:19:03.180: INFO/System.out(1035): getView 6 null type = 0
02-05 15:19:03.190: INFO/System.out(1035): getView 7 null type = 0
02-05 15:19:03.210: INFO/System.out(1035): getView 8 null type = 0
02-05 15:19:03.210: INFO/System.out(1035): getView 9 null type = 1

滚动list:

02-05 15:19:54.160: INFO/System.out(1035): getView 10 null type = 0
02-05 15:19:57.440: INFO/System.out(1035): getView 11 android.widget.LinearLayout@43744528 type = 0
02-05 15:20:01.310: INFO/System.out(1035): getView 12 android.widget.LinearLayout@43744eb0 type = 0
02-05 15:20:01.880: INFO/System.out(1035): getView 13 android.widget.LinearLayout@437456d8 type = 0
02-05 15:20:02.869: INFO/System.out(1035): getView 14 null type = 1
02-05 15:20:06.489: INFO/System.out(1035): getView 15 android.widget.LinearLayout@43745f00 type = 0
02-05 15:20:07.749: INFO/System.out(1035): getView 16 android.widget.LinearLayout@43747170 type = 0
02-05 15:20:10.250: INFO/System.out(1035): getView 17 android.widget.LinearLayout@43747998 type = 0
02-05 15:20:11.661: INFO/System.out(1035): getView 18 android.widget.LinearLayout@437481c0 type = 0
02-05 15:20:13.180: INFO/System.out(1035): getView 19 android.widget.LinearLayout@437468a0 type = 1
02-05 15:20:16.900: INFO/System.out(1035): getView 20 android.widget.LinearLayout@437489e8 type = 0
02-05 15:20:25.690: INFO/System.out(1035): getView 21 android.widget.LinearLayout@4374a8d8 type = 0

convertView对于分割线是空的,直到第一个分割线可见,当其离开屏幕,视图去到Recycler并且convertView开始起作用。

本文翻译自http://android.amberfog.com/?p=296

代码下载:MultipleItemsList.zip – source code