ViewPager :页面的滑动PagerSlidingTabStrip :第三方的自定义View,使得菜单栏和下面的页面产生联动的效果。ListView 列表视图WebView 控件:详情页面加载网址Volley 框架:是网络加载数据的框架Universal-image-loader 图片加载框架PagerSlidingTabStrip 第三方定义view的使用ViewPager ,上面为 PagerSlidingTabStrip ,两个控件可以相互影响,点击“+”,可以跳转到频道订阅界面。把 background_tab.xml 导入drawable中
attrs.xml 是关于自定义View属性的xml文件
第三方view
导入所需要的包
可以嵌套在ViewPager中的Fragment布局
写一个能够将访问的网址都存放的类
布局所对应的Activity代码的编写。
在 MainActivity.java 中声明控件:
ViewPager mainVp; //显示标题,很多个文本组成
PagerSlidingTabStrip tabStrip; //显示fragment
ImageView addIv;
之后在 OnCreate 中通过 findViewById 找到这些控件:
mainVp=findViewById(R.id.main_vp);
tabStrip=findViewById(R.id.main_tabstrip);
addIv=findViewById(R.id.main_iv_add);
addIv需要实现点击跳转到下级页面中,这里让整个Activity实现接口 OnClickListener ,然后重写点击事件。
新建一个activity AddItemActivity ,在布局 activity_add_item.xml 进行布局,整体为线性布局,上面的频道订阅显示为相对布局,中间一条分割线,下面是一个ListView:

接下来写对应的Item的布局,在Layout文件下创建一个新的布局 item_add_lv.xml ,这个左右结构,选择相对布局。

在 MainActivity 中需要实现点击加号按钮实现响应事件,之后跳转到刚才的 AddItemActivity
//实现点击加号从MainActivity跳转到AddItemActivity界面
public void onClick(View v) {
switch (v.getId()){
case R.id.main_iv_add:
Intent intent = new Intent(MainActivity.this, AddItemActivity.class);
startActivity(intent);
break;
}
}
在 AddItemActivity 中添加控件声明和寻找控件:
//声明控件
ImageView backIv;
ListView addLv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add_item);
//查找控件
backIv=findViewById(R.id.add_iv_back);
addLv=findViewById(R.id.add_lv);
}
backIv 要实现返回上一级的功能,在这里依然是实现 OnClickListener 的接口,然后重写 onClick 方法。首先给 backIv 设置监听:
backIv.setOnClickListener(this); //添加点击事件的监听
因为当前的Activity实现了 OnClickListener 这个接口,所以这个Activity的对象就是这个接口的对象,要向backIv中传入 OnClickListener 的接口对象,就可以直接传入他的实现类Activity的对象,所以这里传 this 即可。
backIv 被点击之后的事件可以在 onClick 方法中执行:
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.add_iv_back:
finish(); //销毁当前的Activity,返回上一级界面
break;
}
}
此时 backIv 的操作已写完。
接下来就是写对 addLv 的操作,它是用来显示所有的频道信息, ListView addLv 中的数据源应该是之前写的 TypeBean , TypeBean 中就封装了title、URL和是否显示。
//数据源
List<TypeBean>mDatas;
由于信息是会改变的,当这次选中的频道,我们希望下次进入之后还会保持上一次选中的结果,所以这里需要本地存储,这里选择的本地存储为数据库。
新建一个关于数据库的包 db ,然后创建一个数据库的管理类 DBOpenHelper ,使其继承于 SQLiteOpenHelper ,
public class DBOpenHelper extends SQLiteOpenHelper {
public DBOpenHelper(@Nullable Context context) {
super(context, "info.db", null, 1);
}
@Override
public void onCreate(SQLiteDatabase db) {
String sql="create table itype(id integer primary key,title varchar(10) unique not null,url text not null,isshow varchar(10) not null)";
db.execSQL(sql);
String inserSql="insert into itype values(?,?,?,?)";
db.execSQL(inserSql,new Object[]{1,"头条", NewsURL.headline_url,"true"});
db.execSQL(inserSql,new Object[]{2,"社会",NewsURL.society_url,"true"});
db.execSQL(inserSql,new Object[]{3,"国内",NewsURL.home_url,"true"});
db.execSQL(inserSql,new Object[]{4,"国际",NewsURL.entertainment_url,"true"});
db.execSQL(inserSql,new Object[]{5,"娱乐",NewsURL.entertainment_url,"true"});
db.execSQL(inserSql,new Object[]{6,"体育",NewsURL.sport_url,"false"});
db.execSQL(inserSql,new Object[]{7,"军事",NewsURL.military_url,"false"});
db.execSQL(inserSql,new Object[]{8,"科技",NewsURL.science_url,"false"});
db.execSQL(inserSql,new Object[]{9,"财经",NewsURL.fiance_url,"false"});
db.execSQL(inserSql,new Object[]{10,"时尚",NewsURL.fashion_url,"false"});
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
其中true或false决定了该栏目是显示还是隐藏。
接下来写一个获取数据库中全部信息的集合。在数据库的包 db 中新建一个数据库的管理类 DBManager ,在这里写一个关于数据库声明的函数,再添加一个获取数据库中全部类型的list集合:
public class DBManager {
public static SQLiteDatabase database;
public static void initDB(Context context){
DBOpenHelper helper=new DBOpenHelper(context);
database=helper.getWritableDatabase();
}
/*获取数据库中全部行的内容,存储到集合当中*/
public static List<TypeBean>getAllTypeList(){
List<TypeBean>list=new ArrayList<>();
Cursor cursor=database.query("itype",null,null,null,null,null,null);
while (cursor.moveToNext()){
int id = cursor.getInt(cursor.getColumnIndex("id"));
String title = cursor.getString(cursor.getColumnIndex("title"));
String url = cursor.getString(cursor.getColumnIndex("url"));
String showstr = cursor.getString(cursor.getColumnIndex("isshow"));
Boolean isshow = Boolean.valueOf(showstr);
TypeBean typeBean=new TypeBean(id,title,url,isshow);
list.add(typeBean);
}
return list;
}
}
将数据库的声明 database 放到全局变量中,在 UniteApp.java 中添加:
DBManager.initDB(this); //声明全局的数据库对象
在 AddItemActivity 需要的就是数据库中的所有信息,这里可以直接调用 DBManager 方法来获取:
mDatas= DBManager.getAllTypeList();
此时数据源就有了,接下来要创建适配器对象,写一下ListView的适配器对象:新建一个java class AddItemAdapter ,让它继承于 BaseAdapter ,重新里面的四个方法:
public class AddItemAdapter extends BaseAdapter {
Context context;
List<TypeBean>mDatas;
//通过构造方法将上面两个内容传递进来
public AddItemAdapter(Context context, List<TypeBean> mDatas) {
this.context = context;
this.mDatas = mDatas;
}
@Override
public int getCount() {
return mDatas.size(); //返回一共显示的字段
}
@Override
public Object getItem(int position) {
return mDatas.get(position); //返回当前位置的数据源
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
convertView= LayoutInflater.from(context).inflate(R.layout.item_add_lv,null);
//初始化convertView当中的控件
TextView nameTv=convertView.findViewById(R.id.item_add_tv);
final ImageView iv=convertView.findViewById(R.id.item_add_iv);
//获取指定位置的数据
final TypeBean typeBean=mDatas.get(position); //获取到当前位置的数据源
nameTv.setText(typeBean.getTitle());
//当isShow()设置为true的时候,对应的后面为对号,当isShow()为false的时候,对应的后面为加号,就是不选中
if (typeBean.isShow()){
iv.setImageResource(R.mipmap.subscribe_checked);
}else {
iv.setImageResource(R.mipmap.subscribe_unchecked);
}
//为了避免所有的选项都没有选中ViewPager没有东西可以显示,默认前两项是选中的
if (position == 0 || position == 1) {
iv.setVisibility(View.INVISIBLE);
}else {
iv.setVisibility(View.VISIBLE);
convertView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
typeBean.setShow(!typeBean.isShow()); //改变选中的状态
if (typeBean.isShow()) {
iv.setImageResource(R.mipmap.subscribe_checked);
} else {
iv.setImageResource(R.mipmap.subscribe_unchecked);
}
}
});
}
return convertView;
}
}
接下来就在 AddItemActivity 中创建适配器对象和设置适配器:
//创建适配器对象
adapter = new AddItemAdapter(this, mDatas);
//设置适配器
addLv.setAdapter(adapter);
至此这个界面完成。
每次选中想要订阅的频道,想要在下次打开app的时候还是保留上次选中的频道,还需要把点击的内容进行提交。
onPause 是Activity中的一个生命周期,表示失去焦点时调用的方法,Activity一共有七个生命周期: onCreate (创建了) 、 onStart(启动) 、 onResume(获取焦点)、 onPause (失去焦点)、 onStop (停止) 、 onDestroy(销毁)、 onRestart(重新启动)。
当一个Activity跳转到另一个界面,该Activity就会处于先onPause(失去焦点),再onStop(停止) 的阶段,并没有销毁,因为它依然在栈当中存在着,当返回到这个Activity界面之后,首先会执行onRestart(重新启动),不会执行创建,再执行onStart(启动)
所以 onRestart (重新启动)是失去焦点但是并没有销毁,重新获得焦点之后所执行的生命周期。
这些生命周期都不需要我们自己调用,Android底层会根据Activity的状态自动调用
所以这里可以用生命周期的状态来决定,这里一旦Activity的失去焦点,说明它已经被销毁(这里就是被销毁掉了,因为没有做跳转界面的操作),这里可以将本次选中的内容进行保留、提交。
所以这里可以写一下对于数据修改的方法。
在 DBOpenHelper 中添加:
/*修改数据库当中信息的选中记录*/
public static void updateTypeList(List<TypeBean>typeList){
for (int i = 0; i < typeList.size(); i++) {
TypeBean typeBean = typeList.get(i);
String title = typeBean.getTitle();
ContentValues values = new ContentValues();
values.put("isshow",String.valueOf(typeBean.isShow()));
database.update("itype",values,"title=?",new String[]{title}); //在主线程中直接修改数据库(该数据库数据量比较少可以这样做)
}
}
之后在 AddItemActivity 中添加如下代码,当该页面失去焦点时候,修改数据库:
@Override
protected void onPause() {
super.onPause();
DBManager.updateTypeList(mDatas);
}
运行程序之前先把之前安装的app卸载掉,因为数据库只有在刚装的时候才会执行onCreate方法,如果是更新的话就不再执行onCreate方法了,而是执行onUpdate方法。
效果如下:
这里先不管ViewPager页数是否改变,可以看到可以正常返回上一级页面,在下次打开app的时候还会是保留上次选中的频道,说明 AddItemActivity 对于数据库的操作是正确的。
ViewPager页数的改变是获取数据库的信息,下面介绍。
原文:https://www.cnblogs.com/yangdd/p/13341275.html