传送门:Android+Sqlite 实现古诗阅读应用(一)

  Hi,又回来了,最近接到很多热情洋溢的小伙伴们的来信,吼开心哈,我会继续努力的=-=!

  上回的东西我们做到了有个textview能随机选择诗来进行显示,这也是我做这个东西的初衷,我想找我到底有哪些古诗没有读过,更想感受一下风吹哪页看哪页的闲适(扯远了=-=!),所以功能现在差不多算是结束了,

不过一个古诗应用这么丑可不行,还有就是,我找到了我要的诗我也得能收藏啊,要是下次忘了可怎么办啊,所以这里面还有一些知识点,我们能从接下来的功能中学到:

1.再做一个启动界面:

  打开数据库,随着数据库的增大会有一点卡顿,我们加个界面来过渡缓解一下:

 package com.lfk.poem;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation; /**
* Created by Administrator on 2015/4/11.
*/
public class Opening extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final View view = View.inflate(this, R.layout.activity_opening, null);
setContentView(view);
//渐变展示启动屏
AlphaAnimation start = new AlphaAnimation(0.3f,1.0f);
start.setDuration();
view.startAnimation(start);
start.setAnimationListener(new Animation.AnimationListener()
{
@Override
public void onAnimationEnd(Animation arg0) {
Log.e("linc", "---start!");
try{
Intent intent = new Intent();
intent.setClass(Opening.this,MainActivity.class);
Opening.this.startActivity(intent);
Opening.this.finish();
}
catch(Exception e)
{
e.printStackTrace();
}
}
@Override
public void onAnimationRepeat(Animation animation) {}
@Override
public void onAnimationStart(Animation animation) {}
}); }
}

这是做过的样子:

    

2.修改Actionbar为透明的叠加模式:

  这个我在之前的博客里已经写过了,可以参考一下即时通讯的第五篇:http://www.cnblogs.com/lfk-dsk/p/4419418.html

3.数据库的导入:

  上次为了测试我们只导入了5首古诗作为测试,这回用正则表达式调整了格式,导入了唐诗三百首。

  

将txt做成了这种格式,然后倒入数据库管理软件。

  

数据库里的格式就是这样的了,然后替换数据库就好了,想要现成的可找我要。

4.背景和刷新:

  自然不用说添加自己喜欢的古风背景就好。

  刷新我不用Button了,改用google的下拉刷新,我在这个博文里写过:http://www.cnblogs.com/lfk-dsk/p/4433319.html

  每次刷新一下就会重新找一首诗。

5.主活动的修改

 package com.lfk.poem;

 import android.app.Activity;
import android.content.Intent;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Typeface;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.support.v4.widget.SwipeRefreshLayout;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast; import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream; public class MainActivity extends Activity {
private final int BUFFER_SIZE = 400000;
public static final String DB_NAME = "poem_all.db"; //保存的数据库文件名
public static final String DB_USER_NAME = "poem_user.db";
public static final String PACKAGE_NAME = "com.lfk.poem";// 应用的包名
public static final String DB_PATH = "/data"
+ Environment.getDataDirectory().getAbsolutePath() +"/"
+ PACKAGE_NAME+ "/databases"; // 在手机里存放数据库的位置
private SwipeRefreshLayout swipeLayout;
private RelativeLayout main_layout;
private TextView textView;
private static int ID = 0;
private String NAME;
private String POEM;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); Typeface typeface = Typeface.createFromAsset(getAssets(),"fonts/font_ksj.ttf");
textView = (TextView)findViewById(R.id.text_view);
textView.setTypeface(typeface); main_layout = (RelativeLayout)findViewById(R.id.main_layout);
ChangeBackground();
FindaPoem();
swipeLayout = (SwipeRefreshLayout) this.findViewById(R.id.swipe_refresh);
swipeLayout.setColorScheme(R.color.haah);
swipeLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
new Handler().postDelayed(new Runnable() {//延迟跳转=-=
public void run() {
swipeLayout.setRefreshing(true);
FindaPoem();
swipeLayout.setRefreshing(false);
}
}, 500);
}
});
}
private void FindaPoem() {
int ll = (int) (1 + Math.random() * (59170));
ID = ll;
SQLiteDatabase database = openDatabase();
Cursor cursor = database.rawQuery("Select * From poem Where _id = " + ll, null);
cursor.moveToFirst();
String poem = cursor.getString(1)+"\n"+"\n"+cursor.getString(2)+"\n"+"\n"+cursor.getString(13);
NAME = cursor.getString(2)+": "+cursor.getString(1);
POEM = cursor.getString(13);
Log.e(poem, "================");
textView.setText(poem);
cursor.close();
database.close();
}
private void ChangeBackground(){
int ln = (int) (1 + Math.random() * (5));
switch (ln){
case 1:
main_layout.setBackgroundDrawable(getResources().getDrawable(R.drawable.detail_bg));
break;
case 2:
main_layout.setBackgroundDrawable(getResources().getDrawable(R.drawable.navigation_1));
break;
case 3:
main_layout.setBackgroundDrawable(getResources().getDrawable(R.drawable.navigation_2));
break;
case 4:
main_layout.setBackgroundDrawable(getResources().getDrawable(R.drawable.navigation_3));
break;
case 5:
main_layout.setBackgroundDrawable(getResources().getDrawable(R.drawable.navigation_4));
break;
}
}
public SQLiteDatabase openDatabase() {
try {
File myDataPath = new File(DB_PATH);
if (!myDataPath.exists())
{
myDataPath.mkdirs();// 如果没有这个目录,则创建
}
String dbfile = myDataPath+"/"+DB_NAME;
if (!(new File(dbfile).exists())) {// 判断数据库文件是否存在,若不存在则执行导入,否则直接打开数据库
InputStream is;
is = this.getResources().openRawResource(R.raw.poem_all); // 欲导入的数据库
FileOutputStream fos = new FileOutputStream(dbfile);
byte[] buffer = new byte[BUFFER_SIZE];
int count = 0 ;
while ((count = is.read(buffer)) > 0) {
fos.write(buffer, 0, count);
}
fos.close();
is.close();
}
SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(dbfile, null);
Log.e("=======================","get it ======================");
return db;
} catch (FileNotFoundException e) {
Log.e("Database", "File not found");
e.printStackTrace();
} catch (IOException e) {
Log.e("Database", "IO exception");
e.printStackTrace();
}
return null;
}
void AddaPoemToCollect(){
File myDataPath = new File(DB_PATH);
String dbfile = myDataPath+"/"+DB_USER_NAME;
SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(dbfile, null);
//ContentValues contentValues = new ContentValues();
db.execSQL("UPDATE poem SET ticai = 1 WHERE _id ="+ID);
//db.insert("book", null, contentValues);
db.close();
Toast.makeText(getApplicationContext(),
"Collect succeed",
Toast.LENGTH_SHORT).show();
//ID++;
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu_main, menu);
return super.onCreateOptionsMenu(menu);
} @Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
switch(id){
case R.id.collect:
Intent intent = new Intent(this,Collect.class);
startActivity(intent);
break;
case R.id.like:
AddaPoemToCollect();
break;
} return super.onOptionsItemSelected(item);
}
}

  这是修改过的主活动。

  1.首先更换了字体放在assets文件夹内,在res里面,没有的请新建。

  Typeface typeface = Typeface.createFromAsset(getAssets(),"fonts/font_ksj.ttf");
textView = (TextView)findViewById(R.id.text_view);
textView.setTypeface(typeface);

获取了字体资源,注册了一个textview,把字体设置为textview。

    

这是修改过的效果,纤细的字体很适合我们的古诗!

  2.

     private void ChangeBackground(){
int ln = (int) (1 + Math.random() * (5));
switch (ln){
case 1:
main_layout.setBackgroundDrawable(getResources().getDrawable(R.drawable.detail_bg));
break;
case 2:
main_layout.setBackgroundDrawable(getResources().getDrawable(R.drawable.navigation_1));
break;
case 3:
main_layout.setBackgroundDrawable(getResources().getDrawable(R.drawable.navigation_2));
break;
case 4:
main_layout.setBackgroundDrawable(getResources().getDrawable(R.drawable.navigation_3));
break;
case 5:
main_layout.setBackgroundDrawable(getResources().getDrawable(R.drawable.navigation_4));
break;
}
}

  添加了一个修改背景的函数,每次进入会随机选择背景,这样我们每次进入就有可能看到不一样的背景了。

  3.

     private void FindaPoem() {
int ll = (int) (1 + Math.random() * (59170));
ID = ll;
SQLiteDatabase database = openDatabase();
Cursor cursor = database.rawQuery("Select * From poem Where _id = " + ll, null);
cursor.moveToFirst();
String poem = cursor.getString(1)+"\n"+"\n"+cursor.getString(2)+"\n"+"\n"+cursor.getString(13);
NAME = cursor.getString(2)+": "+cursor.getString(1);
POEM = cursor.getString(13);
Log.e(poem, "================");
textView.setText(poem);
cursor.close();
database.close();
}

  从数据库里随即一个数(我数据库里有59170首诗,=-=!)然后打开数据库,找到ID为此项的诗,然后获取诗的内容,getString的号码要按照你自己的数据库需要选择不同的栏位,

比如0位就是ID的栏位,我这里面作者古诗名和古诗内容是分开存放的,而且加入了不少我要用的数据,所以栏位增加到了13个之多,自己做的话只需要三个栏位就好,一个id,一个古诗内容,

一个收藏标记位(用0和1来标记)

  所以我对dbhelper的数据库生成类进行了一些修改:

 package com.lfk.poem;

 import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.widget.Toast; /**
* Created by Administrator on 2015/5/8.
*/
public class DBhelper extends SQLiteOpenHelper {
private static final String CREAT_DB = "create table book ("
+ "id integer primary key autoincrement,"
+ "collect int,"
+ "poem text)";
private Context mcontext; public DBhelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
mcontext = context;
} @Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CREAT_DB);
Toast.makeText(mcontext,"succeed collect!",Toast.LENGTH_SHORT).show();
} @Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}

  这样生成的数据库就能成功的应用收藏功能了,上一步所说的修改数据库也就能实现了。

6.收藏功能的实现:

  我在写这篇博文之前曾经写过两次关于收藏的内容,第一次的方法比较蠢,我又开了一个用户的数据库,然后把要收藏的东西复制进用户数据库中,不过这种方法比较麻烦,

首先是开两个数据库增加了系统的无谓开销,增加了对系统资源的消耗,而且在传入新的数据库中,id会发生变化,写入和传值会非常的不便利,所以我放弃了那种方法,改用

在数据库设置标志栏位的方法来解决问题。

  

 package com.lfk.poem;

 import android.app.Activity;
import android.content.Intent;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast; import java.io.File; public class Collect extends Activity {
private DBhelper dBhelper;
private ListView listView;
public static ArrayAdapter<String> mArrayAdapter;
public static final String DB_NAME = "poem_all.db"; //保存的数据库文件名
public static final String PACKAGE_NAME = "com.lfk.poem";// 应用的包名
public static final String DB_PATH = "/data"
+ Environment.getDataDirectory().getAbsolutePath() +"/"
+ PACKAGE_NAME+ "/databases"; // 在手机里存放数据库的位置
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_collect);
String[] data = new String[0];
//dBhelper = new DBhelper(this,"poem_all.db",null,1);
listView = (ListView)findViewById(R.id.list_view);
mArrayAdapter = new ArrayAdapter<String>(this,R.layout.list_item);
listView.setAdapter(mArrayAdapter);
FindyourCollect();
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
long arg3) {
System.out.println(arg2);
String temp = (String)((TextView)arg1).getText();
Intent intent = new Intent();
intent.putExtra("title",temp);
System.out.println(arg2);
intent.setClass(Collect.this, Collect_item.class);
startActivity(intent);
Toast.makeText(getApplicationContext(),
"Opening " + arg2,
Toast.LENGTH_SHORT).show();
mArrayAdapter.notifyDataSetChanged();
}
});
} // @Override
// public boolean onCreateOptionsMenu(Menu menu) {
// // Inflate the menu; this adds items to the action bar if it is present.
// getMenuInflater().inflate(R.menu.menu_collect, menu);
// return true;
// }
//
// @Override
// public boolean onOptionsItemSelected(MenuItem item) {
// // Handle action bar item clicks here. The action bar will
// // automatically handle clicks on the Home/Up button, so long
// // as you specify a parent activity in AndroidManifest.xml.
// int id = item.getItemId();
//
// //noinspection SimplifiableIfStatement
// if (id == R.id.action_settings) {
// return true;
// }
//
// return super.onOptionsItemSelected(item);
// }
void FindyourCollect(){
File myDataPath = new File(DB_PATH);
String dbfile = myDataPath+"/"+DB_NAME;
SQLiteDatabase database = SQLiteDatabase.openOrCreateDatabase(dbfile, null);
Cursor cursor = database.rawQuery("Select * From poem where ticai = 1", null);
Log.e("===================", "================");
if(cursor.moveToFirst()) {
Log.e("===================", "================");
do {
String title = cursor.getString(cursor.getColumnIndex("mingcheng"));
mArrayAdapter.add(title);
Log.e(title, "================");
}while (cursor.moveToNext());
}
cursor.close();
database.close();
}
@Override
protected void onRestart(){
super.onRestart();
mArrayAdapter.clear();
FindyourCollect();
mArrayAdapter.notifyDataSetChanged();
}
}

这是Collect的活动的代码,代码中用了一个系统自带的简易的listview(主要是也不需要太多的功能),进入之后运行FindyourCollect()方法用Select * From poem where ticai = 1语法,

寻找标志位,然后把所有找到的东西加入listview中去,然后设置item的响应打开。

 package com.lfk.poem;

 import android.app.Activity;
import android.content.Intent;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Typeface;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.TextView;
import android.widget.Toast; public class Collect_item extends Activity {
private DBhelper dBhelper;
private String ID;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_collect_item);
Intent intent = getIntent();
String title = intent.getStringExtra("title");
//System.out.println(id+"=================");
TextView textView = (TextView)findViewById(R.id.poem_item);
Typeface typeface = Typeface.createFromAsset(getAssets(),"fonts/font_ksj.ttf");
textView.setTypeface(typeface);
dBhelper = new DBhelper(this,"poem_all.db",null,1);
SQLiteDatabase database = dBhelper.getWritableDatabase();
Cursor cursor = database.rawQuery("Select * From poem where mingcheng="+"\""+title+"\"", null);
cursor.moveToFirst();
ID = cursor.getString(cursor.getColumnIndex("_id"));
String poem = cursor.getString(1)+"\n"+"\n"+cursor.getString(2)+"\n"+"\n"+cursor.getString(13);
textView.setText(poem);
Log.e("===================", "================");
cursor.close();
database.close();
} @Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_collect_item, menu);
return true;
} @Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId(); if(id == R.id.dislike_collect){
SQLiteDatabase db = dBhelper.getWritableDatabase();
db.execSQL("UPDATE poem SET ticai = 0 WHERE _id ="+ID);
db.close();
Toast.makeText(getApplicationContext(),
"Collect Delete",
Toast.LENGTH_SHORT).show();
} return super.onOptionsItemSelected(item);
} }

打开后的方法比较简单和主活动基本一样,接受传入的题目,然后根据题目找到我们需要的诗,设置字体然后textview中显示出来。

然后就是加入收藏了,为了方便,我把加入收藏写进了meau中以方便使用:

  void AddaPoemToCollect(){
//File myDataPath = new File(DB_PATH);
//String dbfile = myDataPath+"/"+DB_USER_NAME;
SQLiteDatabase db = openDatabase();
//ContentValues contentValues = new ContentValues();
db.execSQL("UPDATE poem SET ticai = 1 WHERE _id ="+ID);
//db.insert("book", null, contentValues);
db.close();
Toast.makeText(getApplicationContext(),
"Collect succeed",
Toast.LENGTH_SHORT).show();
//ID++;
}
void deleteAPoemFromCollect(){
SQLiteDatabase db = openDatabase(); db.execSQL("UPDATE poem SET ticai = 0 WHERE _id ="+ID); db.close(); Toast.makeText(getApplicationContext(),
"Collect Delete",
Toast.LENGTH_SHORT).show();
}

这个就是加入收藏和删除收藏的方法所在了,我在主活动和收藏的内容活动中都为meau添加了这个方法,并且设置了一个全局变量ID用于删除和加入收藏的时候寻址。

到此为止我们初期的功能就都开发完了,放出新的界面,图片还是暂时借用了别人的成例,我已经找UI帮我做更好看的界面了:

            

            

            

            

好了这一篇就说这么多吧,应该还会有一些新的有意思的功能要尝试,所以应该还会有后续吧!

么么哒,喜欢就点赞吧!!!

Android+Sqlite 实现古诗阅读应用(二)的更多相关文章

  1. Android+Sqlite 实现古诗阅读应用(三)

    往期传送门: Android+Sqlite 实现古诗阅读应用(一) Android+Sqlite 实现古诗阅读应用(二) 加入截图分享的功能. 很多应用都有分享的功能,我也想在我的古诗App里加入这个 ...

  2. Android+Sqlite 实现古诗阅读应用(一)

    不说网络app,很多本地的app都有一些随机的内容推送,比如随机推送一些小知识,古诗,名言名画什么的,界面制作的好看一点就能看起来特别的文艺范, 最近就是看了这样的一些应用,就想自己实现一下,这种方法 ...

  3. 《阿里巴巴Android编码规范》阅读纪要(二)

    版权声明:本文出自汪磊的博客,转载请务必注明出处. 本篇继续上一篇<阿里巴巴Android编码规范>阅读纪要(一) ,还是建议各位同学有时间完整阅读一下<阿里巴巴Android编码规 ...

  4. 【原】FMDB源码阅读(二)

    [原]FMDB源码阅读(二) 本文转载请注明出处 -- polobymulberry-博客园 1. 前言 上一篇只是简单地过了一下FMDB一个简单例子的基本流程,并没有涉及到FMDB的所有方方面面,比 ...

  5. Android SQLite总结(一) (转)

    Android SQLite总结(一)  郑海波 2012-08-21 转载请声明:http://blog.csdn.net/nuptboyzhb/article/details/7891887 前言 ...

  6. Android SQLite 数据库详细介绍

    Android SQLite 数据库详细介绍 我们在编写数据库应用软件时,需要考虑这样的问题:因为我们开发的软件可能会安装在很多用户的手机上,如果应用使用到了SQLite数据库,我们必须在用户初次使用 ...

  7. Android SQLite 数据库 增删改查操作

    Android SQLite 数据库 增删改查操作 转载▼ 一.使用嵌入式关系型SQLite数据库存储数据 在Android平台上,集成了一个嵌入式关系型数据库--SQLite,SQLite3支持NU ...

  8. Android系统--输入系统(十二)Dispatch线程_总体框架

    Android系统--输入系统(十二)Dispatch线程_总体框架 1. Dispatch线程框架 我们知道Dispatch线程是分发之意,那么便可以引入两个问题:1. 发什么;2. 发给谁.这两个 ...

  9. 再读Android sqlite

    再读Android sqlite Android原生支持sqlite数据库操作,sqlite时轻量级关系型数据库,支持标准sql语句.Android对sqlite进行良好的接口封装来避免sql注入等安 ...

随机推荐

  1. Python multi-thread 多线程 print 如何避免print的结果混乱

    multithread如何写 这是我第一次写multithread,所以就是照着例子学,下面是我用来学的例子 来自于”Automate the boring stuff with Python”的15 ...

  2. C# 如何在Excel 动态生成PivotTable

    Excel 中的透视表对于数据分析来说,非常的方便,而且很多业务人员对于Excel的操作也是非常熟悉的,因此用Excel作为分析数据的界面,不失为一种很好的选择.那么如何用C#从数据库中抓取数据,并在 ...

  3. Git正确的协作方式(很简单)

    最近部门有人书写了一篇很好的Git协作方式,操作也简单,分支能以保持一条干净的线进行协作开发.这里做个笔记,方便之后查看. PS:本文非原创. 原则 不过分相信自己,自己的修改,可能影响所有人 不过分 ...

  4. 原生JS:Math对象详解

    Math对象 本文参考MDN做的详细整理,方便大家参考MDN Math 也是一个内置对象, 为数学常量和数学函数提供了属性和方法,而不是一个函数对象. 与其它全局对象不同的是, Math 不是一个构造 ...

  5. sharepoint2010问卷调查(2)-实现问卷的图片调查(采用自定义字段类型)

    1. 首先建立个图片库上传图片 并建立文件夹1和2,1下有1.1文件夹,2下2.1文件夹,2.1下有文件夹2.1.1. 在1文件夹下放如下图片: 2.建立自定义字段类型,如下图: 3.部署后建立栏目的 ...

  6. 转 java中static{}语句块详解

    原文地址:http://blog.csdn.net/lubiaopan/article/details/4802430     感谢原作者! static{}(即static块),会在类被加载的时候执 ...

  7. Android Studio no debuggable applications解决方案

    android studio 默认是没有开启debuggable 功能的,在tools里打开该功能即可,Tools->Android->Enable ADB Integration. 刚设 ...

  8. Android jni helloworld

    新建Android项目,设置布局: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android& ...

  9. 高仿精仿手机版QQ空间应用源码

    说明:本次QQ空间更新了以前非常基础的代码 更新内容一 更新了登陆界面二  增加了输入时密码时和登陆成功后播放音频的效果三 增加了导航条渐隐的效果(和真实QQ空间的导航条一样,首先透明,当tablev ...

  10. iOS 学习 - 14.本地联系人

    苹果在iOS9的SDK中废除了AddressBookUI.framework的一些功能(是不是这个库都废除了,有待验证),具体和保存联系人相关的几个系统界面如下:联系人选择:AddressBookUI ...