目录
1、LayoutInflater 对象:可以用来加载布局文件的对象。
获取方式:getLayoutInflater()方法
LayoutInflater inflater = getLayoutInflater();
//或者
LayoutInflater inflater = LayoutInflater.from(context);
作用:
使用其 inflate(布局文件,父布局root[,boolean attachToRoot]) 方法,返回一个 View对象。
inflater.inflate(R.layout.layout1,null);
inflater.inflate(R.layout.layout2, root,false);
inflater.inflate(R.layout.layout3, root,true);
- 在不设置attachToRoot参数的情况下,如果root不为null,attachToRoot参数默认为true。
2)如果 root 为null,attachToRoot将失去作用,设置任何值都没有意义。
3)如果 root 不为null,
attachToRoot设为true,则会给加载的布局文件的指定一个父布局,即root。
attachToRoot设为false,则会将布局文件最外层的所有layout属性进行设置,当该view被添加到父view当中时,这些layout属性会自动生效。
2、AlertDialog.Builder 对象 :对话框对象。
获取方式:通过new() 方式,构造方法参数为一个context。
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
其有很多方法,可以用于设置对话框样式:
builder.setIcon(R.drawable.pic)
.setTitle("用户登录")
.setMessage("简单对话框")
.setView(log_view) //可以为一个布局文件,也可以为一个ImageView对象
.setNegativeButton("取消", null)
.setPositiveButton("登录", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {}
});
.setMultiChoiceItems(new String[] {"选项1","选项2","选项3","选项4"}, null, null)
//设置多选框。后两个参数可以为一个boolean[]数组、一个OnMultiChoiceClickListener监听器
.setSingleChoiceItems(new String[] {"选项1","选项2","选项3","选项4"}, null, null)
.setItems(new String[] {"列表项1","列表项2","列表项3"}, null)
//设置列表项,后一个参数可为DialogInterface.OnClickListener() 监听器
builder.create().show();
3 、ArrayAdaptter、SimpleAdapter、BaseAdapter适配器展示列表数据
tips:格式单一的数据 ArrayAdapter、格式多样的数据SimpleAdapter 、BaseAdapter(后者灵活度更高,需要重写适配器类,需要手动将数据放进布局控件中)。
相同点,这三者都是用来适配数据项跟 listView的,将每一项分别作为一行。
因此,我们需要先在整体布局中设计一个listView控件,然后再给适配器们单独设置每行数据的布局。
(1)ArrayAdapter的一种使用方式:
a)编写好布局之后 ,将数据放入一个泛型 list 中;
b)new 一个适配器ArrayAdapter,写入构造方法的四个参数【 context 、每一项数据的布局的文件、每一项对应的布局文件中的控件、数据】;
c)获取主布局的listVew控件,给其 setAdapter,参数中传入适配器;
ps:还可以用 listView 控件的 setOnItemClickListener()方法设置一个AdapterView.OnItemClickListener()监听器。
List<String> data = new ArrayList<>();
data.add("北京");
data.add("上海");
data.add("广州");
final ArrayAdapter<String> adapter1 = new ArrayAdapter<>(
MainActivity.this,
R.layout.itemlayout1,
R.id.textView,
data
);
listView.setAdapter(adapter1);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override//重写onItemClick方法
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {}
}
(2)SimpleAdapter的一种使用方式:
a)同样定义一个泛型 List,类型为 Map。先把每一项数据的各值以 key、value方式放入Map 、再把Map 放入List。
b)同样 new 一个SimpleAdapter,并给构造方法传参【context, 数据,每一项数据的布局的文件,一项数据的 key 数组,每个key 的数据对应的布局的文件的控件】;
c)同样是给listView 设置适配器;
String[] food = new String[]{"北京烤鸭","上海小笼包","广州拉肠"};
int[] images = {R.drawable.duck, R.drawable.baozi, R.drawable.lachang};
List<Map<String, Object>> list_map = new ArrayList<Map<String, Object>>();
for (int i = 0; i<3; i++){
Map<String, Object> items = new HashMap<String, Object>();
items.put("image", images[i]);
items.put("food", food[i]);
list_map.add(items);
}
final SimpleAdapter adapter2 = new SimpleAdapter(
MainActivity.this,
list_map,
R.layout.itemlayout2,
new String[]{"image", "food"},
new int[]{R.id.imageView2, R.id.textView2}
);
listView.setAdapter(adapter2);
(3)BaseAdapter的一种使用方式:
a)定义一个实体类 ,存放每一项的数据,并写入set/get方法;
b)同样定义一个泛型List,类型为自己定义的实体类类型,并把数据都放进去 ;
c)编写一个继承抽象类BaseAdapter的类,完善其抽象方法;
(如果有些方法用不到,可以把自己也定义为抽象类,就不用实现全部了吧?)
重点是在其setView()方法中,找到控件,然后把给其setText为数据项;
ps:为提高效率 ,第一次加载视图时 ,可以定义一个实体类把控件都保存到convertView对象
中;后面每一次可以先判断convertView是否为空 ,若不为空就可以直接在convertView取。
d)同样new一个刚刚编写的适配器类,传参只需要 【context,数据 】
e)同样是给listView 设置适配器 。
//实体类
public class Item {
private int itemImage;
private String itemTitle;
private String itemContent;
public Item(int itemImage, String itemTitle, String itemContent){
this.itemImage = itemImage;
this.itemTitle = itemTitle;
this.itemContent = itemContent;
}
//省略getter/setter方法
}
//自己编写的适配器类
public class TestAdapter extends BaseAdapter {
private List<Item> list;
private LayoutInflater layoutInflater;
public TestAdapter(Context context, List<Item> list){
layoutInflater = LayoutInflater.from(context);
this.list = list;
}
public int getCount(){
return list.size();
}
public Object getItem(int position){
return list.get(position);
}
public View getView(int position, View convertView, ViewGroup parent){
ViewHolder viewHolder;
Item item = list.get(position);
if(convertView == null){
convertView = layoutInflater.inflate(R.layout.itemlayout3, null);
viewHolder = new ViewHolder();
viewHolder.imageView = convertView.findViewById(R.id.imageView3);
viewHolder.title = convertView.findViewById(R.id.title);
viewHolder.content = convertView.findViewById(R.id.content);
convertView.setTag(viewHolder);
}else{
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.title.setText(item.getItemTitle());
viewHolder.content.setText(item.getItemContent());
viewHolder.imageView.setImageResource(item.getItemImage());
return convertView;
}
public static class ViewHolder{
public ImageView imageView;
public TextView title;
public TextView content;
}
}
//主活动
List<Item> list = new ArrayList<>();
list.add(new Item(R.drawable.duck, "北京烤鸭", "热门评价:吃过最好吃的烤鸭!"));
list.add(new Item(R.drawable.baozi, "上海小笼包", "热门评价:汤汁多!"));
list.add(new Item(R.drawable.lachang, "广州拉肠", "热门评价:真香!"));
final TestAdapter adapter3 = new TestAdapter(MainActivity.this,list);
listView.setAdapter(adapter3);
4、导航栏菜单设置 toolbar
1)getSupportActionBar().hide(); 将原始导航栏隐藏;
2)在布局文件中定义一个 toolbar,并获取他;
3)新建一个 menu资源文件,并写入需要的menu item;
4)使用 toolbar 的inflateMenu(menu资源) 方法把菜单加载进去;
5)可以给toolbar 设置一个点击监听器。
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getSupportActionBar().hide();
Toolbar toolbar = findViewById(R.id.toolbar);
toolbar.inflateMenu(R.menu.menu_option);
toolbar.setOnMenuItemClickListener(new MyMenuItemClickListener());
}
private class MyMenuItemClickListener implements Toolbar.OnMenuItemClickListener{
@Override
public boolean onMenuItemClick(MenuItem item) {
//自定义
}
}
5、fragment动态加载
上面适配器的栗子,我们使用了通过判断button的点击监听来分别设计相应的 listView。
现在,我们通过使用fragment ,就可以实现通过button 的监听来动态改变页面 的数据。(只是数据 ,布局不改变)
一个简单栗子:
a)编写实体类BookContent,并在其写入内部类Book以及定义两个静态变量 ITEM(存入三个Book对象的列表)、ITEM_MAP(存入三个Book对象及id的Map);
b)编写类 BookListFragment继承 ListFragment类,在其中定义一个与主Activity 通信的接口,写一个监听方法;
重写父类onCreate 方法,在其中写入用 setListAdapter设置一个 ArrayAdapter适配器 ,适配器的数据为 书信息的列表ITEM,布局直接使用原生布局和原生控件;
重写onAttach方法 ,判断主Activity是否继承通信接口;
重写 onDetach方法,将接口置空;
重写onListItemClick方法 ,添加通信接口的监听处理;
c)编写主布局文件为左右布局,写一个fragment,指定name为刚刚定义的BookListFragment及其包名,与程序连接,展现书信息列表;再写一个framelayout控件,用于动态加载数据 ;
再编写一个布局文件,用于设置framelayout的布局;
d)编写主 Activity,实现与BookListFragment的通信接口,并实现其方法;该方法中,将BookListFragment传过来的id放到 Bundle中并传给 BookDetailFragment类;然后获取fragment管理器,开始事物,即,用 BookDetailFragment类对象取代主布局中的 framelayout;
e)编写 类BookDetailFragment类 ,继承Fragment;
在类中,获取主 Activity传来的参数id,检查数据中是否存在此id,若有 ,则在 onCreateView方法中获取数据展示布局文件并给各控件设置值。
//书本实体类
public class BookContent {
public static class Book{
public Integer id;
public String title;
public String desc;
public Book(int id, String title, String desc){
this.id = id;
this.title = title;
this.desc = desc;
}
@Override
public String toString() {
return title;
}
}
public static List<Book> ITEM = new ArrayList<Book>();
public static Map<Integer, Book> ITEM_MAP = new HashMap<Integer, Book>();
static {
addItem(new Book(1,"数据结构","了解Java基础"));
addItem(new Book(2,"javaWeb","了解Web开发"));
addItem(new Book(3,"高等数学","编程必备数学基础"));
}
private static void addItem(Book book){
ITEM.add(book);
ITEM_MAP.put(book.id,book);
}
}
public class BookListFragment extends ListFragment {
public interface Callbacks{
public void onItemSelected(Integer id);
}
private Callbacks mCallbacks;
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setListAdapter(new ArrayAdapter<BookContent.Book>(getActivity(),
//R.layout.simple_list_item_activated_1:原生布局,代表只有单行text
android.R.layout.simple_list_item_activated_1,android.R.id.text1,
BookContent.ITEM)
);
}
public void onAttach(Activity activity){
super.onAttach(activity);
if(! (activity instanceof Callbacks)){
throw new IllegalStateException("BookListFragment所在的activity必须实现Callbacks接口!");
}
mCallbacks = (Callbacks)activity;
}
public void onDetach(){
super.onDetach();
mCallbacks = null;
}
public void onListItemClick(ListView listView, View view, int position, long id){
super.onListItemClick(listView, view, position, id);
mCallbacks.onItemSelected(BookContent.ITEM.get(position).id);
}
}
public class MainActivity extends AppCompatActivity implements BookListFragment.Callbacks{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void onItemSelected(Integer id){
Bundle bundle = new Bundle();
bundle.putInt(BookDetailFragment.ITEM_ID, id);
BookDetailFragment fragment = new BookDetailFragment();
fragment.setArguments(bundle);
getFragmentManager().beginTransaction()
.replace(R.id.book_detail_container, fragment)
.addToBackStack(null)
.commit();
}
}
public class BookDetailFragment extends Fragment {
public static final String ITEM_ID = "item_id";
BookContent.Book book;
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
if(getArguments().containsKey(ITEM_ID)){
book = BookContent.ITEM_MAP.get(getArguments().getInt(ITEM_ID));
}
}
public View onCreateView(LayoutInflater infater, ViewGroup container, Bundle savedInstanceState){
View rootView = infater.inflate(R.layout.fragment_book_detail, container,false);
if(book != null){
((TextView)rootView.findViewById(R.id.book_title)).setText(book.title);
((TextView)rootView.findViewById(R.id.book_desc)).setText(book.desc);
}
return rootView;
}
}
6 、打电话
(1)直接调用系统电话 ,此时无需权限授予 。
只需给intent 添加个动作,然后startActivity(intent) 即可;
ps:设置默认号码 ,可以给intent setData。
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent();
intent.setAction(Intent.ACTION_DIAL);
intent.setData(Uri.parse("tel:13016033333"));
startActivity(intent);
}
}
(2)在程序内拨打电话 ,需要权限 。
a)先在清单里申请权限:
b)在onCreate时 ,需要先判断用 AtivityCompat类的 checkSelfPermission方法判断权限是否已获得。若是 ,直接执行拨打电话的代码 ;若否 ,则要用AtivityCompat类的 requestPermission方法再次请求 ;
然后 ,在onRequestPermissionResult 方法中再次判断权限是否已获得。若是,执行打电话代码 ;若否,提示无权限 ,销毁自己 ;
c)编写打电话代码 ,获取输入电话控件的值 ,给intent设置动作以及值;给拨号按钮设置监听事件 。
//程序内编写电话功能
public class MainActivity extends AppCompatActivity {
EditText editText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if(ActivityCompat.checkSelfPermission(MainActivity.this, Manifest.permission
.CALL_PHONE) != PackageManager.PERMISSION_GRANTED){
ActivityCompat.requestPermissions(MainActivity.this, new String[]{
Manifest.permission.CALL_PHONE}, 1);
}else{
fun();
}
}
public void fun(){
editText = findViewById(R.id.number);
findViewById(R.id.call).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent();
intent.setAction(intent.ACTION_CALL);
intent.setData(Uri.parse("tel:" + editText.getText().toString()));
startActivity(intent);
}
});
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode){
case 1:
if(grantResults[0] == PackageManager.PERMISSION_GRANTED){
fun();
}else{
Toast.makeText(this,"无电话权限",Toast.LENGTH_SHORT).show();
finish();
}
}
}
}
7 、发短信
(1)跟打电话一样 ,直接调用系统短信 ,无需权限,给intent设个动作就好了:
public class MainActivity extends AppCompatActivity {
//调用系统发短信功能
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent();
intent.setAction(intent.ACTION_SENDTO);
intent.setData(Uri.parse("sms:10086?body=短信程序设计"));
startActivity(intent);
}
}
(2)在程序内发送短信 ,需要先在清单申请权限:
a)同样是判断权限是否已获得动作 ;不同的是,这此处有多个权限 ,可以把他们先放进数组里,用循环判断 ;另外再拿一个列表来放没获得的权限 ,最后把这个列表转成数组再次判断;
b)获得权限后,执行发短信代码:分三步走:先用 getSmsManage获得短信管理员 ;再让管理员 divideMessage把短信切成合适长度,放进一个列表里面;最后逐个发送 sendTextMessage。
//程序内实现发短信
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
String[] permissions = new String[]{
"android.permission.SEND_SMS",
"android.permission.READ_PHONE_STATE"
};
ArrayList<String> mPermission = new ArrayList();
for(int i=0; i<permissions.length; i++) {
if (ActivityCompat.checkSelfPermission(MainActivity.this, permissions[i]) !=
PackageManager.PERMISSION_GRANTED){
mPermission.add(permissions[i]);
}
}
if(mPermission.isEmpty()){
fun();
}else{
String[] needPermission = mPermission.toArray(new String[mPermission.size()]);
ActivityCompat.requestPermissions(this, needPermission, 1);
}
}
public void fun(){
findViewById(R.id.sendBtn).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
EditText recevier = findViewById(R.id.recevierNum);
EditText centent = findViewById(R.id.smsContent);
SmsManager smsManager =SmsManager.getDefault();
List<String> list = smsManager.divideMessage(centent.getText().toString());
for(String sms:list){
smsManager.sendTextMessage(recevier.getText().toString(), null,
sms,null,null);
}
}
});
}
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode){
case 1:
for(int i=0; i<permissions.length; i++){
if(grantResults[i] != PackageManager.PERMISSION_GRANTED){
Toast.makeText(this,"权限不足",Toast.LENGTH_SHORT).show();
finish();
}
}fun();
}
}
}
8 、拍照保存
a)同样 ,先申请拍照权限:
b)同样 ,检查权限是否获得 ,若无进行再处理;
c)编写 执行拍照的方法 ,即给设置一个拍照 intent ,然后 startActivityForResult;
d)编写 onActivityResult 方法,在内部存储中新建一个放照片的文件夹;用一个位图对象去接收intent 中的数据;将位图压缩后的数据放在一个放在文件夹下的输出流中 ;把输出流缓冲区的东西真正的放进内存 ;并用 photo对象把位图显示。
public class MainActivity extends AppCompatActivity {
ImageView photo;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if(ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) ==
PackageManager.PERMISSION_GRANTED){
fun();
}else{
ActivityCompat.requestPermissions(MainActivity.this,new String[]{
Manifest.permission.READ_EXTERNAL_STORAGE
}, 1);
}
}
void fun(){
photo = findViewById(R.id.photo);
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(intent, 1);
}
public void onActivityResult(int requestCode, int resultCode, Intent data){
super.onActivityResult(requestCode,resultCode,data);
String basePath = Environment.getExternalStorageDirectory().getPath();
String filePath = basePath + "/testImage";
if(requestCode ==1 ){
if(resultCode == RESULT_OK);{
Bundle bundle = data.getExtras();
Bitmap bitmap = (Bitmap) bundle.get("data");
FileOutputStream fos = null;
File file = new File(filePath);
file.mkdir();
String fileName = filePath + "/4-6.jpg";
try{
fos = new FileOutputStream(fileName);
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
}catch (Exception e){
e.printStackTrace();
}finally {
try {
fos.flush();
}catch (IOException e){
e.printStackTrace();
}
}photo.setImageBitmap(bitmap);
}
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode){
case 1:
if(grantResults[0] == PackageManager.PERMISSION_GRANTED){
fun();
}else{
Toast.makeText(this,"没有SD卡权限",Toast.LENGTH_SHORT).show();
finish();
}
}
}
}