当前位置:  编程技术>移动开发
本页文章导读:
    ▪UItableViewCell的复用机制,原懂得答        UItableViewCell的复用机制,原理解答今天在看iphone开发秘籍的时候,遇到这个问题,就仔细的深入了一下,通过测试,获取了一些自认为还不错的结论,希望对大家在cell复用方面遇到的一些问.........
    ▪ 申请googleMap服务并且显示map(基础篇)        申请googleMap服务并且显示地图(基础篇)我会按照先后顺序写出来,包括源代码 1.打开命令行方式,找到debug.keystore文件 注意:使用android开发一年以上,keystore文件将失效,带来的问题是模拟.........
    ▪ 发送短信与通电话简单例子       发送短信与打电话简单例子package mars.com; import java.util.List; import android.app.Activity; import android.app.PendingIntent; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.telephony.SmsM.........

[1]UItableViewCell的复用机制,原懂得答
    来源: 互联网  发布时间: 2014-02-18
UItableViewCell的复用机制,原理解答

今天在看iphone开发秘籍的时候,遇到这个问题,就仔细的深入了一下,通过测试,获取了一些自认为还不错的结论,希望对大家在cell复用方面遇到的一些问题会有所帮助。

本篇文章只讲原理,对于如果对cell做界面,不深入讲述。鉴于我的表达能力有限,可能会有我自己清楚,但是却说不清楚的地方,如有问题,留言给我。


UITableView在界面的编程用的甚多,iphone开发也三月有余了,每次用到cellForRowAtIndexPath的委托方法的时候,都是直接copy代码,自己略加一些界面的修改,对于cell的标示符都是static NSString* identifier = @"cell";然后调用dequeueReusableCellWithIdentifier方法获取cell,如果cell为空,再调用[[[UITableViewCellalloc]initWithStyle方法新创建一个,根本没有考虑过更深一些的东西。为了讲解清楚,现放上一段代码,代码copy自iphone开发秘籍,本人为了讲解,略加修改。以下所有讲解均依照此代码进行,因此,如果您希望能够透彻的了解cell的复用机制,建议实际运行以下,跟着讲解,查看效果。代码只有tableVIew的委托方法,因此您需要自己创建工程,把这些委托方法加进去。


上文一共四个委托方法,表明tableView一个section,有32行,高度为58.关于tableView的高度那个委托方法的返回的高度值,建议最好自己运行程序查看以下,最终达到一页的界面显示8个cell,第8个cell显示一半也行,但是不能显示9和7个cell。我这里之所以为58,由于(480 - 44)/ 58 为7.5 的样子,44为navigationBar的高度,480为屏幕的高度。总之,需要达到的效果是一页显示7个多的cell。还有那个icon.png需要自己准备了,要把它显示出来。是不是很麻烦呀?没办法,谁让我们在获得知识呢,知识总是需要点功夫的。


- (NSInteger)numberOfSectionsInTableView:(UITableView *)aTableView 
{ 
	return 1; 
}

- (NSInteger)tableView:(UITableView *)aTableView numberOfRowsInSection:(NSInteger)section 
{
	return 32;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
	return 58;
}
- (UITableViewCell *)tableView:(UITableView *)tView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
	UITableViewCellStyle style;
	NSString *cellType;
	
	switch (indexPath.row % 4)
	{
		case 0:
			style = UITableViewCellStyleDefault;
			cellType = @"Default Style";
            //有标题没有正文(没有细节文字)。可选的图片
			break;
		case 1:
			style = UITableViewCellStyleSubtitle;
			cellType = @"Subtitle Style";
            //标题和正文方式,上下排布。可选的图片
			break;
		case 2:
			style = UITableViewCellStyleValue1;
			cellType = @"Value1 Style";
            //左边文字左对齐,右边文字右对齐。可选的图片
			break;
		case 3:
			style =  UITableViewCellStyleValue2;
			cellType =  @"Value2 Style";
            //左边文字右对齐,蓝色;右边文字左对齐,黑色。没有图片
			break;
			
	}
	static int i = 0;
	UITableViewCell *cell = [tView dequeueReusableCellWithIdentifier:cellType];
	if (!cell) 
    {
		cell = [[[UITableViewCell alloc] initWithStyle:style reuseIdentifier:cellType] autorelease];
        ++i;
        NSLog(@"cell created %d times", i);
    }
	
	if (indexPath.row > 3) 
		cell.imageView.image = [UIImage imageNamed:@"icon.png"];
	
	cell.textLabel.text = cellType;
	cell.detailTextLabel.text = @"Subtitle text";
	return cell;
}


首先讲解一下复用队列:

复用队列的元素增加:只有在cell被滑动出界面的时候,此cell才会被加入到复用队列中。每次在创建cell的时候,程序会首先通过调用dequeueReusableCellWithIdentifier:cellType方法,到复用队列中去寻找标示符为“cellType”的cell,如果找不到,返回nil,然后程序去通过调用[[[UITableViewCell alloc] initWithStyle:style reuseIdentifier:cellType] autorelease]来创建标示符为“cellType”的cell。

先运行一次程序,不要滑动cell,查看打印日志,会有打印"cell create 1 times",,,"cell create 8 times",一共有8个日志,表明cell创建了8次,这个日志打印是在cellForRowAtIndexPath中的创建cell的时候打印的。然后慢慢向下(向下的意思,实际上是手向上滑动,让界面显示下一个cell,向上与之相反)滑动cell,到显示第九个cell的时候,会看到打印一条日志"cell create 9 times",然后继续慢慢向下滑动,会有"cell create 10 times",直到滑动到第12个cell以后,cell被创建了12个之后,以后再怎么滑动,cell都不会被创建了。也就是说本tableView要完整的工作,一共创建了12个cell。

开始解释原因了:

第一页的界面一共需要展示8个cell,故而cell需要创建8次,每一个cell负责自己的数据显示。此8个创建以后,复用队列依然为空(因为你此时还没有滑动cell呢,复用队列的元素不会增加)。然后在向下滑动显示出第9个cell的时候,还会调用cellForRowAtIndexPath方法,在此方法中,它首先到可复用队列中去找,由于此时队列为空,它创建了一个cell,打印日志,同时当第1个cell滑动出界面之外,第一个cell进入到复用队列中,队列中有一个元素,此元素的表示符为@"Default Style"。然后继续向下滑动cell,开始显示第10个cell,它同样到复用队列中去找,第10个cell的标示符为@"Subtitle Style",但是队列中唯一的cell的标示符为@"Default Style",根据标示符寻找,没有找到,故而再次创建一个新的cell,同时将滑动出界面的第2个cell进入复用队列。此时复用队列有两个元素,标示符为@"Default Style",@"Subtitle Style"。同样的道理,滑动到第11个cell的时候,第3个cell入队,第12个cell的时候,第4个cell入队。此时复用队列的元素个数为四个,标示符分别为:@"Default Style",@"Subtitle Style",@"Value1 Style",@"Value2 Style".然后继续滑动cell,当滑动到第13个cell的时候,它的标示符为@"Default Style",它到复用队列中去找,可以找到。故而,这个cell就不会被创建了,同理,再次向下滑动,以下的所有cell都可以根据标示符找到对应的cell,不会有被创建的。在向下滑动的过程中,滑动出去的cell会被入队,不过只入队创建了的cell,也就是说最终队列中会有12个cell。对于每次取对应标示符的元素,到底取的是哪一个?采用的什么策略?这个我不知道,我通过打印查看的是在向下滑动的过程中,一直顺着队列找,队列是一个循环队列。向上滑动的时候,逆着队列向上找,由于是循环队列,一直在转圈。

如果你仔细看的话,你会发现第一个cell本来没有图片,为什么一划下去再次滑动(如果滑动的距离远,一次搞定,如果滑动的距离近,多上下滑动几次)上来又有图片了呢?这个就要思考一个:第一个cell在滑出界面又划入界面的时候,是从复用队列拿到的。复用队列有12个元素,第1,5,9还第一个cell有相同的标示符,第1个没有图片,第5个和第9个有图片。当用户复用的是第一个cell的时候,它是没有图片,当用户复用第5,9个cell的时候,它是有图片的。因此,当你上下滑动,查看第一个cell的时候,你会看到它一会有图片,一会没有图片。这个跟复用时候的队列查找规则有关。


实用篇:

说了那么多,全是关于原理的。现在说点实用的。如果你想在所有的cell中添加一个按钮,你是应该在if中添加,还是应该在if之外添加呢?毫无疑问,应该在if中,如果你是在if的外面添加的,那会导致,你在向下滑动cell的过程中,取出来的cell本来已经带有button了,而你还在addSubview,按钮越来越多。或者你可以采用在if外面添加,前提是每次先cell remove掉其所有的子视图。这样太消耗cpu,麻烦了。如果你想一行隔着一行有按钮和没有按钮,你该怎么做呢?稍微思考一下,这个可是两种风格的cell,故而在滑出界面进行重用的时候,它们应该属于不同的标示符。于是你在创建cell的时候,应该去指定两种标示符,创建两种cell。当然,也许你聪明了,我是不是可以在if之外先remove掉cell的所有子视图,然后根据row % 2 == 0或者!=0 来进行addSubView:button吗?答案当然是肯定的,但是这样还是同样的问题,太消耗cpu了。平常我们给每一个cell添加了一个button,肯定要添加事件的。对于不同的button,响应不同的事件?那么我是不是通过在if语句中给button设置它的tag标记(例如button.tag = indexpath.row)来实现呢?哈哈,你应该足够聪明了吧,当然不行。你可以这样想,if语句是用来创建的,它只被执行了(例如上面的例子:12次),但是你可能有几百行的cell,当然你的tag也就只有12个了,明显不对应。像这样的,应该怎么处理呢?答案是:放在if的外面。你在if外面设置了tag标记,当然,在某一个具体的时间点上,仍然只有12个标记,但是这12个标记是可变的,例如当前界面显示第100-111号的cell,那么此时的button的tag就会是100-111了,仍然是12个按钮,但是它们会根据用户的滑动,进行不同的tag切换,相当于拥有了很多个按钮。如果你没有被我说的话给弄晕,脑袋又足够清醒的话,你应该可以得出以下的结论:对于界面的定制,放在if中比较好,一个cell中只创建一次;对于数据的定制,放在if外面比较好,对于不同的cell,表示不同的内容,虽然只有12个cell,但是cell中存放的数据我可以任意的映射。如果你得出了这个结论,那么如果在加上textField,label等等,你应该可以轻松搞定。不仅仅是表面上,更重要的是,你理解了原理,掌握了机制,万变都不怕,即使有新的需求,脑袋想想,或者拿着这篇文章看看,希望能给你一些启示。



    
[2] 申请googleMap服务并且显示map(基础篇)
    来源: 互联网  发布时间: 2014-02-18
申请googleMap服务并且显示地图(基础篇)

我会按照先后顺序写出来,包括源代码

1.打开命令行方式,找到debug.keystore文件

注意:使用android开发一年以上,keystore文件将失效,带来的问题是模拟器无法自动生成apk文件,解决方法是删除此文件,重新启动eclipse就OK了。

输入指令:cd .android回车

然后输入keytool -list -alias androiddebugkey -keystore debug.keystore -v(千万不要输错奥)

接下来要你输入密钥库口令,输入android就行了,详细的如下图


然后把MD5记下来,准备申请google api key

2.申请google api key

打开下面这个网址https://developers.google.com/android/maps-api-signup?hl=zh-CN

然后输入你的MD5,然后就会得到google api key 了

如下图


然后就可以进行下面了。

说来也奇怪,我第一次申请的时候,页面总是不能完全打开,我就找了好多翻墙软件,结果也不行,不知道为什么总是得不到,但是后来过了几天,就可以申请了,这真是个问题,有机会大家可以给我说说这事为什么?奇怪了。好,不扯淡了,继续下面的

3.建立android项目,注意要建立的项目是在google api 上建立的,相信大家都知道,建立工程的时候注意一下就行了,这里就不出图了。

4.下面就是我建立的工程的代码,非常简单,只是为了测试使用,不能放大缩小,只能显示地图,代码如下

这个是manifest.xml文件,需要注册联网,以及使用googlemap的库(library)

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="mars.com"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk android:minSdkVersion="10" />

    <uses-permission android:name="android.permission.INTERNET" />

    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" >
        <activity
            android:name=".GoogleMapDemoActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <uses-library android:name="com.google.android.maps" />
    </application>

</manifest>
main.xml文件如下,就不多解释了,上面有图,就照着官网的弄就行了。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <com.google.android.maps.MapView
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:apiKey="0aVeWdF7g8mo7Q-S3rDHcpmANgEF9752OHJlh0g" />

</LinearLayout>
activity文件如下
package mars.com;

import android.os.Bundle;
import com.google.android.maps.MapActivity;

public class GoogleMapDemoActivity extends MapActivity {
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
	}

	@Override
	protected boolean isRouteDisplayed() {//是否导航
		return false;//不导航
	}
}
注意,是MapActivity千万别写错。。。好,今天到此为止




    
[3] 发送短信与通电话简单例子
    来源: 互联网  发布时间: 2014-02-18
发送短信与打电话简单例子
package mars.com;

import java.util.List;
import android.app.Activity;
import android.app.PendingIntent;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.telephony.SmsManager;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

public class TelephoneCallActivity extends Activity {
	private Button call;
	private EditText input;
	private EditText message;
	private Button sendMsg;

	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		call = (Button) findViewById(R.id.call);
		input = (EditText) findViewById(R.id.input);
		message = (EditText) findViewById(R.id.message);
		sendMsg = (Button) findViewById(R.id.sendmsg);

		sendMsg.setOnClickListener(new OnClickListener() {
			public void onClick(View v) {
				String str = message.getText().toString();
				if (str == null) {
					Toast.makeText(TelephoneCallActivity.this, "没有输入电话号码",
							Toast.LENGTH_SHORT).show();
					return;
				}

				SmsManager sm = SmsManager.getDefault();
				List<String> texts = sm.divideMessage(str);
				for (String string : texts) {
					sm.sendTextMessage(input.getText().toString(), null,
							string, null, null);
				}
				// ******另外一种发送短信
				/*String strNo = input.getText().toString();
				String strContent = message.getText().toString();

				SmsManager smsManager = SmsManager.getDefault();

				PendingIntent sentIntent = PendingIntent.getBroadcast(
						TelephoneCallActivity.this, 0, new Intent(), 0);

				// 如果字数超过30,需拆分成多条短信发送
				if (strContent.length() > 30) {
					List<String> msgs = smsManager.divideMessage(strContent);
					for (String msg : msgs) {
						smsManager.sendTextMessage(strNo, null, msg,
								sentIntent, null);
					}
				} else {
					smsManager.sendTextMessage(strNo, null, strContent,
							sentIntent, null);
				}
				Toast.makeText(TelephoneCallActivity.this, "短信发送完成",
						Toast.LENGTH_LONG).show();*/
			}
		});

		call.setOnClickListener(new OnClickListener() {
			public void onClick(View v) {
				String str = input.getText().toString();
				if (str == null) {
					Toast.makeText(TelephoneCallActivity.this, "没有输入电话",
							Toast.LENGTH_SHORT).show();
					return;
				}
				Intent intent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:"
						+ str));
				startActivity(intent);
			}
		});

	}
}

xml文件如下

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/a1" />

    <EditText
        android:id="@+id/input"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:digits="1234567890"
        android:inputType="text"
        android:numeric="integer"
        android:phoneNumber="true" />

    <Button
        android:id="@+id/call"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/call" />

    <TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/a2" />

    <EditText
        android:id="@+id/message"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:inputType="text" />

    <Button
        android:id="@+id/sendmsg"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/msg" />

</LinearLayout>

别忘了添加权限呀,
manifest文件中的内容如下

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="mars.com"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk android:minSdkVersion="8" />

    <uses-permission android:name="android.permission.CALL_PHONE" />
    <uses-permission android:name="android.permission.SEND_SMS" />

    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" >
        <activity
            android:name=".TelephoneCallActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>




    
最新技术文章:
▪Android开发之登录验证实例教程
▪Android开发之注册登录方法示例
▪Android获取手机SIM卡运营商信息的方法
▪Android实现将已发送的短信写入短信数据库的...
▪Android发送短信功能代码
▪Android根据电话号码获得联系人头像实例代码
▪Android中GPS定位的用法实例
▪Android实现退出时关闭所有Activity的方法
▪Android实现文件的分割和组装
▪Android录音应用实例教程
▪Android双击返回键退出程序的实现方法
▪Android实现侦听电池状态显示、电量及充电动...
▪Android获取当前已连接的wifi信号强度的方法
▪Android实现动态显示或隐藏密码输入框的内容
▪根据USER-AGENT判断手机类型并跳转到相应的app...
▪Android Touch事件分发过程详解
▪Android中实现为TextView添加多个可点击的文本
▪Android程序设计之AIDL实例详解
▪Android显式启动与隐式启动Activity的区别介绍
▪Android按钮单击事件的四种常用写法总结
▪Android消息处理机制Looper和Handler详解
▪Android实现Back功能代码片段总结
▪Android实用的代码片段 常用代码总结
▪Android实现弹出键盘的方法
▪Android中通过view方式获取当前Activity的屏幕截...
▪Android提高之自定义Menu(TabMenu)实现方法
▪Android提高之多方向抽屉实现方法
▪Android提高之MediaPlayer播放网络音频的实现方法...
▪Android提高之MediaPlayer播放网络视频的实现方法...
▪Android提高之手游转电视游戏的模拟操控
 


站内导航:


特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

©2012-2021,,E-mail:www_#163.com(请将#改为@)

浙ICP备11055608号-3