部分安卓功能实现过程(未完待续)
一、TabHost实现底部切换
1.布局
a、使用TabHost作为布局文件的根节点,并给其id赋值为:android:id="@android:id/tabhost"
b、用FrameLayout作为内容更换的显示节点,并给其id赋值为:android:id="@android:id/tabcontent"
c、用TabWidget作为选项卡的节点,并给其id赋值为:android:id="@android:id/tabs"。
大致布局为:
<TabHost>
<FrameLayout>
</FrameLayout>
<TabWidget>
</TabWidget?
</TabHost>
2.逻辑实现
a.生成选项卡,此处的setIndicator()方法可以传入一个view布局。
TabHost.TabSpec tabSpec1 = getTabHost().newTabSpec("clear_cache").setIndicator("缓存清理");
TabHost.TabSpec tabSpec2 = getTabHost().newTabSpec("clear_sdCard").setIndicator("sd卡清理");
b.告知点中选项卡的后续操作(如点击打开另一个Activity)
tabSpec1.setContent(new Intent(this,CacheClearActivity.class));
tabSpec2.setContent(new Intent(this,SdCardCleanActivity.class));
c.将选项卡维护到host(宿主)中
getTabHost().addTab(tabSpec1);
getTabHost().addTab(tabSpec2);
二、SlidingDrawer实现滑动拖拽界面
该控件只能由右往左、下往上滑动,若需要滑动到一半,
则在布局添加一个view占据一定的空间即可
1.添加SlidingDrawr标签,并添加以下属性
android:handle="@+id/handler"
android:content="@+id/content"
android:orientation="horizontal"
//horizontal代表由右往左滑动,vertical代表由下往上滑动。
2.在其中添加子控件,并给其子控件赋予同上的id属性。
<ImageView
android:id="@id/handler"/>
<TextView
android:id="@id/content"/>
//android:handle="@+id/handler" 把手
//android:content="@+id/content" 抽屉
三、Fragment实现底部切换视图(类似QQ)
1.新建多个Fragment子类继承Fragment
实现其中的onCreateView方法,并在该方法中填充布局。
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
//View view = inflater.from(R.layout.fragment1,container,false);
View view = View.inflate(getContext(),R.layout.fragment1,null);
return view;
}
2.在主界面Activity
在布局xml文件中添加一个Framlayout布局标签,用此来替换各个Fragment的显示。
类文件中,通过响应不同Fragment按钮的事件来替换Framlayout中不同的碎片布局。
replaceFragment(new Fragment1());
.
.
.
private void replaceFragment(Fragment fragment){
FragmentManager fm = getSupportFragmentManager(); //获取碎片管理器
FragmentTransaction ft = fm.beginTransaction(); //开启碎片事务
ft.replace(R.id.fl_fragment,fragment); //在事务中替换碎片
ft.commit(); //提交碎片
}
3.在碎片和活动之间通信
通过方法来获取Fragment1的实例,进而在活动中调用碎片的方法。
Fragment1 fragment1 = (Fragment1)getFragmentManager()
.findFragmentById(R.id.fragment1);
在碎片中调用getActivity()方法来获得和当前碎片相关联的活动示例。
MainActivity activity = (MainActivity)getActivity();
四、ScrollView中嵌入ListView,GridView冲突的解决(让ListView全显示出来)
1.方法一(Bug多,一般用法二):把ListView放在LinearLayout 中,再给listview一个具体的高度,就可以显示多行了
如:
<ScrollView android:layout_width="fill_parent"
android:layout_height="fill_parent">
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<ListView
android:layout_width="fill_parent"
android:layout_height="400dp"
android:id="@+id/lv"></ListView>
</LinearLayout>
</ScrollView>
2.方法二:自定义可适应ScrollView的ListView,定义类继承ListView,并重写onMeasure()方法。
/**
* 重写该方法,达到使ListView适应ScrollView的效果
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
}
五.FragmentTabHost实现底部菜单导航
1.FragmentTabHost用法
它的子控件为TabSpec,其中有Idcator属性,再其中的View包含ImageView和TextView。
首先继承FragmentActivity(AppCompatActivity是继承FragmentActivity的),调用setup()方法,添加TabSpec
2.Select背景选择器
1.Fragment实现步骤
布局文件布局:
<FrameLayout
android:id="@+id/realtabcontent"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:background="@color/colorPrimary"></FrameLayout>
<android.support.v4.app.FragmentTabHost
android:id="@android:id/tabhost"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="@color/white"
>
<!--必须写,官方要求-->
<FrameLayout
android:id="@android:id/tabcontent"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="0"
></FrameLayout>
</android.support.v4.app.FragmentTabHost>
Activit实现逻辑:其中Tab为一个JavaBean,将一个导航view对象化(包括图标、标题及Fragment)
mTabHost = (FragmentTabHost)findViewById(android.R.id.tabhost);
mTabHost.setup(this,getSupportFragmentManager(),R.id.realtabcontent);
for(Tab tab : mTabs){
TabHost.TabSpec tabSpec = mTabHost.newTabSpec(getString(tab.getTitle()));
tabSpec.setIndicator(buildIndicator(tab)); //此处传入布局
mTabHost.addTab(tabSpec,tab.getFragment(),null);
}
mTabHost.getTabWidget().setShowDividers(LinearLayout.SHOW_DIVIDER_NONE); //去掉分割线
mTabHost.setCurrentTab(0); //设置默认选中第一个
搭建导航view
private View buildIndicator(Tab tab){
View view = mInflater.inflate(R.layout.tab_indicator,null);
ImageView icon_tab = (ImageView)view.findViewById(R.id.icon_tab);
TextView tv_tab = (TextView)view.findViewById(R.id.tv_tab);
icon_tab.setBackgroundResource(tab.getIcon());
tv_tab.setText(tab.getTitle());
return view;
}
2.按键按下及获取焦点,图片发生改变.
在drawable下新建select.xml文件,然后根据状态设置背景图片:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_focused="false" android:state_selected="false"
android:state_pressed="false" android:drawable="@mipmap/home_icon"/>
<!--Selected states-->
<item android:state_focused="false" android:state_selected="true"
android:state_pressed="false" android:drawable="@mipmap/home_select_icon"/>
<!--Focused states-->
<item android:state_focused="true" android:state_selected="false"
android:state_pressed="false" android:drawable="@mipmap/home_select_icon"/>
<item android:state_focused="true" android:state_selected="true"
android:state_pressed="false" android:drawable="@mipmap/home_select_icon"/>
<!--Pressed-->
<item android:state_focused="true" android:state_pressed="true"
android:drawable="@mipmap/home_select_icon"/>
<item android:state_pressed="true" android:drawable="@mipmap/home_select_icon"/>
</selector>
在Activity中导航按钮的ImageView设置为此布局文件:
icon_tab.setBackgroundResource(tab.getIcon()); //getIcon()就是R.drawable.select
3.点击实现字体颜色发生改变
在res文件夹下新建color文件夹,在其中新建selector_tab_text.xml文件,写入:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_selected="true" android:color="#eb4f48" />
<item android:state_active="true" android:color="#eb4f38"/>
<item android:state_selected="false" android:color="#a9b7b7"/>
<item android:state_active="false" android:color="#a9b7b7" />
</selector>
在布局文件中的TextView控件中添加属性:
android:textColor="@color/selector_tab_text"
3.底部菜单的几种实现方式。
TabHost + activity(弃用)
RadioButton + Fragment
FragmentTabHost + Fragment
六.toolBar的使用
布局文件的加入TooBar控件,
<!--添加导航键,只需加入属性:android:navigationIcon="@mipmap/refresh_m"-->
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:navigationIcon="@mipmap/refresh_m"
app:title="title"
></android.support.v7.widget.Toolbar>
添加导航键监听事件:
toolbar = (Toolbar)findViewById(R.id.toolbar);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//导航键监听事件
Toast.makeText(getApplicationContext(),"点击了导航键",Toast.LENGTH_SHORT).show();
}
});
添加并绑定menu:
toolbar.inflaterMenu(R.menu.menu_main);//R.menu.main是放在res下的menu文件夹下的
添加点击监听事件:
toolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
int id = item.getItemId();
//...
return true;
}
});
七.自定义ToolBar
八.使用开源项目实现图片轮播
使用方法及项目地址参看:[https://github.com/daimajia/AndroidImageSlider/wiki/Custom-Indicators](http://note.youdao.com/)
九.RecycleView实现多组列表视图展示
十.OkHttp实现网络通信并用Gson解析json数据
Picasso.with(mContext).load(urlImag).into(view); //从网络下载图片并缓存至view
十一.Fresco图片加载组件
在5.0以下系统,Fresco将图片放到一个特别的内存区域。在图片不显示的时候,占用的内存会自动释放。给图片分配内存的方式:Ashmem(系统匿名共享内存)。支持gif格式
十二.使用xutils简化找控件的操作
@ViewInject(R.id.image_view);
在onCreate()方法中加入:
ViewUtils.inject(this);
十二.下拉刷新SwipeRefreshLayout控件
作为父控件来包含ListView、RecycleView等子控件,实现下拉刷新的刷新图标显示。
也可使用github开源的MaterialRefreshLayout控件来实现下拉刷新,上拉加载。地址:[https://github.com/android-cjj/Android-MaterialRefreshLayout](http://note.youdao.com/)
十三.封装RecycleView的Adapter并实现列表展示
**RecyclerView基本使用方法**,需为其添加的数据适配器是需要继承Recycle.Adapter,
并指定泛型一个继承自RecyclerView.ViewHolder的类,并添加构造方法对Item中的子控件进行初始化。
同时重写onCreateViewHolder()、onBindViewHolder()和getItemCount()这3个方法。
此次封装简化了RecycleView的使用,不在需要考虑ViewHolder中的多个控件属性,我们只需要自定义一个Adapter(如下面的TestBeanAdapter)继承自SimpleAdapter类,并加载自身的构造函数,同时实现其中的bindData()方法即可,即为每个Item对应的View控件绑定数据。
1.声明一个类BaseAdapter继承RecyclerView。ViewHolder。
指定泛型
public abstract class BaseAdapter<T,H extends BaseViewHolder> extends RecyclerView.Adapter<BaseViewHolder>{
//1.数据使用泛型
protected List<T> mDatas;
protected LayoutInflater mInflater;
protected Context mContext;
protected int mLayoutResId;
private OnItemClickListener listener;
public interface OnItemClickListener{
void OnClick(View view, int position);
}
public void setOnItemClickListener(OnItemClickListener listener){
this.listener = listener;
}
public BaseAdapter(Context context, List<T> datas, int layoutResId){
this.mDatas = datas;
this.mContext = context;
this.mLayoutResId = layoutResId;
mInflater = LayoutInflater.from(context);
}
@Override
public BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = mInflater.inflate(mLayoutResId,null,false);
return new BaseViewHolder(view, listener);
}
@Override
public void onBindViewHolder(BaseViewHolder holder, int position) {
T t = getItem(position);
bindData(holder,t);
}
@Override
public int getItemCount() {
return mDatas.size();
}
public T getItem(int postion){
return mDatas.get(postion);
}
public abstract void bindData(BaseViewHolder viewHolder, T t);
}
2.新建一个BaseViewHolder继承自RecyclerView.ViewHolder并实现OnclickListener.
public class BaseViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
private BaseAdapter.OnItemClickListener listener;
private SparseArray<View> views;
public BaseViewHolder(View itemView, BaseAdapter.OnItemClickListener listener) {
super(itemView);
//mItemView = itemView;
views = new SparseArray<>();
this.listener = listener;
itemView.setOnClickListener(this);
}
public View getView(int id){
return findView(id);
}
public TextView getTextView(int id){
return findView(id);
}
public ImageView getImageView(int id){
return findView(id);
}
public Button getButtonView(int id){
return findView(id);
}
private <T extends View> T findView(int id){
View view = views.get(id);
if(view == null){
view = itemView.findViewById(id);
views.put(id,view);
}
return (T) view;
}
@Override
public void onClick(View v) {
listener.OnClick(v,getLayoutPosition());
}
}
3.SimpleAdapter继承BaseAdapter
为了减少一个泛型参数。并添加构造函数,初始化参数。
public abstract class SimpleAdapter<T> extends BaseAdapter<T,BaseViewHolder>{
public SimpleAdapter(Context context, List<T> datas, int layoutResId) {
super(context, datas, layoutResId);
}
}
4.新建一个TestBeanAdapter 继承自SimpleAdapter对象即。
添加构造函数,并覆写bindData()方法,即在此方法中为每个Item中的View进行初始化赋值。
public class TestBeanAdapter extends SimpleAdapter<TestBean>{ //新建的TestBeanAdapter就直接使用定好的布局文件
public TestBeanAdapter(Context context, List<TestBean> datas) {
super(context, datas, R.layout.test_adapter_item);
}
@Override
public void bindData(BaseViewHolder viewHolder, TestBean testBean) {
//为每个Item添加并绑定数据
TextView tv_test_item_left = (TextView) viewHolder.getView(R.id.tv_test_item_left); //条目布局文件中的子控件
TextView tv_test_item_right = viewHolder.getTextView(R.id.tv_test_item_right); //直接用在ViewHolder中封装好的函数
tv_test_item_left.setText(testBean.getName());
tv_test_item_right.setText(testBean.getSex());
}
}
5.使用方法
使用时需新建步骤(1、2)或(1、2、3、4)中的类文件,对应使用下面(1)或(2)的使用方法。
注意:在使用LinearLayoutManager时会出现每个Item只能占据一部分,即不能适配Item的布局(原因暂时未知,有人解释是RecyclerView的bug),将其改为GridLayoutManager就能进行适配布局。
其中参数datas,为TestBean的一个数组,而TestBean是一个将Item中的View进行赋值而保存的JavaBean。
rl_test = (RecyclerView)mView.findViewById(R.id.rl_test);
GridLayoutManager layoutManager = new GridLayoutManager(getContext(),1);
//用LinearLayoutManager会出现问题,每个Item只会占据有内容的一部分
//LinearLayoutManager layoutManager = new LinearLayoutManager(getContext());
rl_test.setLayoutManager(layoutManager);
for(int i = 0;i<10;i++){
TestBean bean = new TestBean("sannas"+ i,"man");
datas.add(bean);
}
public class TestBean {
private String name;
private String sex;
public TestBean(String name, String sex) {
this.name = name;
this.sex = sex;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
(1)直接使用BaseAdapter。
BaseAdapter<TestBean,BaseViewHolder> mAdatper = new BaseAdapter<TestBean,BaseViewHolder>(getContext(),datas,R.layout.test_adapter_item) {
//R.layout.test_adapter_item为每个条目的布局文件
@Override
public void bindData(BaseViewHolder viewHolder, TestBean testBean) {
TextView tv_test_item_left = (TextView) viewHolder.getView(R.id.tv_test_item_left); //条目布局文件中的子控件
TextView tv_test_item_right = viewHolder.getTextView(R.id.tv_test_item_right); //直接用在ViewHolder中封装好的函数
tv_test_item_left.setText(testBean.getName());
tv_test_item_right.setText(testBean.getSex());
}
};
mAdatper.setOnItemClickListener(new BaseAdapter.OnItemClickListener() {
@Override
public void OnClick(View view, int position) {
//
Toast.makeText(getActivity(),"点击了第"+ position +"个Item",Toast.LENGTH_SHORT).show();
}
});
rl_test.setAdapter(mAdatper);
(2)使用将Item的View对象的值实例化成为一个Bean对象之后并进行初始化之后的TestBeanAdapter。
TestBeanAdapter mAdatper = new TestBeanAdapter(getContext(),datas);
mAdatper.setOnItemClickListener(new BaseAdapter.OnItemClickListener() {
@Override
public void OnClick(View view, int position) {
Toast.makeText(getActivity(),"点击了第"+ position +"个Item",Toast.LENGTH_SHORT).show();
}
});
rl_test.setAdapter(mAdatper);
Switch控件
使用下面两个属性可以改变开关的按钮及北京图片
android:thumb="@drawable/bike"
android:track="@drawable/boat"