Android练习项目之基于Studio构建Material Design风格谈话管理系统
2015-09-23 15:23
375 查看
话不多说,先看效果图
学习android开发有几个月了,一直都是做做单个功能的小练习,最近正好有个公司用混合模式开发AppCan做的一个谈话管理项目,我用android原生将其基本实现,除了用于练习客户端与服务器的通信方法,也是对Google大力推行的Material Design的一个实践与尝试。
可以说MD是未来Android的发展方向,越来越多的成熟软件都采用了该设计模式,未来必将是一种设计趋势。
点击了解 Material Design中文版
使用Activity嵌套ViewPager嵌套Fragment来实现页面的作用滑动,点击Tab跳转。
使用AsyncHttpClient框架进行网络通信,并且通过cookie来保持登录状态,实现客户端登录持久化。
AsyncHttpClient框架
使用了GitHub上面大量的开源UI框架,实现了Material Design风格。
Material Design开源框架库集合
只需在项目根目录下的build.gradle中添加上面几行代码,即可在编译时自动下载所需依赖包,这是我放弃Eclipse转用Studio最看重的一个方面,实在是太方便了。
我的xml布局就不说了,只放了两个TextView显示两行文字,
实现思路很简单,通过开启线程打开新的页面,给线程设置等待时间就可以了。
看源码:
SplashActivity.java
其中淡入淡出的xml资源如下(淡出相反)
R.anim.fade_in.xml
EditText使用框架库,实现hint文字动态悬浮,获得焦点变色等效果。
CheckBox使用框架库,实现动画改变选中状态。
Button使用框架库,实现扁平化设计风格和点击ripple波纹效果。
activity_login.xml (只保留主要部分)
登录页面Activity需要继承自com.blunderer.materialdesignlibrary.activities.Activity,然后重写需要重写的方法。
不要在onCreate中调用setContentView方法来设置布局资源
在重写方法getContentView中调用布局资源
需要单独封装AsyncHttpClient类,才能实现之后每次请求都保持登录状态,即设置cookie
使用SharePreferences来本地存储用户名和密码
创建用户信息类UserBean,通过get和set方法读写用户信息
创建服务器配置类ServerConfig来全局化配置服务器参数
通过重写onCreateOptionsMenu方法加载menu资源
通过重写onOptionsItemSelected设置menu监听
LoginActivity.java 实现源码
用户信息类示例 UserBean.java
AsyncHttpClient封装类
cookie处理类
重写必须重写的方法
在getViewPagerHandler方法中加载Fragment对象
expandTabs方法中,true:扩展Tab占满屏幕宽,false相反
defaultViewPagerPageSelectedPosition方法设置默认选择tab
onCreateOptionsMenu方法加载menu资源
onOptionsItemSelected方法设置menu点击事件
在点击注销按钮时创建一个dialog,此处需要注意
AlertDialog.Builder builder = new AlertDialog.Builder(this);
此时参数Context可以传入this,因为是在Activity类中;
若在Fragment中,则不能使用this或是getApplicationContext( ),要使用getActivity( ),否则报错
MainActivity.java
首先看看布局资源
fragment_talk_list.xml
下面看Fragment实现源码
继承自android.support.v4.app.Fragment
onCreateView方法用于加载布局资源
newInstance方法用于获取Fragment实例
调用jsonArrayToMapList方法将服务端返回JsonArray转存为List< Map >对象
bindToListView方法把数据绑定到CardView中显示
需要自己写ViewHolder类并且继承自RecyclerView.ViewHolder
需要自己写卡片点击事件监听器接口OnCardViewClickListener
onCreateViewHolder方法中加载CardView布局资源
该Adapter需要继承RecyclerView.Adapter< TalkListAdapter.ViewHolder >,泛型需要指定为自定义的ViewHolder类
该Adapter需要实现View.OnClickListener接口,在onClick方法中调用自定义的卡片点击监听器接口的onItemClick方法。
至此,该项目的主要功能基本就实现了,一些比较简单的就没写出,主要是给自己的项目练习做个总结,方便以后有需要的时候回顾,也希望能让更多初学者能从中多少获得一些收获,共同进步。
再次表达一下对Material Design的喜爱之情,真的是太棒了,看看那些大神们封装的各种控件库,真的是美的不行不行的,完全秒杀iPhone的界面设计了我觉得。
有问题可私信我,有共同学习的小伙伴联系我,需要源码也可以找我。QQ12547345
学习android开发有几个月了,一直都是做做单个功能的小练习,最近正好有个公司用混合模式开发AppCan做的一个谈话管理项目,我用android原生将其基本实现,除了用于练习客户端与服务器的通信方法,也是对Google大力推行的Material Design的一个实践与尝试。
开发平台IDE
本项目首先在Eclipse上进行开发,但是在引用GitHub上面各个大神的Material Design Library时,非常不方便,大部分都没有封装成jar包,最后果断放弃,转用Android Studio进行开发,虽然编译速度很慢,但是在添加支持库、依赖方面实在是太给力了,下面再详细说。Material Design
Material Design是Google公司在2014年I/O大会上提出的一种全新的设计模式,即以扁平化为主,通过引入Z轴、阴影的变化、水波纹等来体现“Material(物质、材料)”的概念。可以说MD是未来Android的发展方向,越来越多的成熟软件都采用了该设计模式,未来必将是一种设计趋势。
点击了解 Material Design中文版
本项目特点
本项目使用了作为Material Design主推的RecyclerView和CardView两种控件,用于代替ListView,更大程度上发挥了列表视图的功能与扩展能力,使用FloatActionButton实现浮动按钮。使用Activity嵌套ViewPager嵌套Fragment来实现页面的作用滑动,点击Tab跳转。
使用AsyncHttpClient框架进行网络通信,并且通过cookie来保持登录状态,实现客户端登录持久化。
AsyncHttpClient框架
使用了GitHub上面大量的开源UI框架,实现了Material Design风格。
Material Design开源框架库集合
项目配置
添加项目依赖[code]dependencies { compile 'com.android.support:recyclerview-v7:22.2.0' //v7包中的RecyclerView compile 'com.android.support:cardview-v7:22.2.0' //v7包中的CardView compile 'com.android.support:appcompat-v7:22.0.1' //v7包中的Appcompat compile 'com.blunderer:materialdesignlibrary:2.0.4' //GitHub开源MD框架库 compile 'com.rengwuxian.materialedittext:library:2.1.4' //GitHub开源EditText库 compile 'com.github.rey5137:material:1.2.1' //GitHub开源普通Button库 compile 'com.loopj.android:android-async-http:1.4.8' //GitHub开源网络请求框架 compile 'com.getbase:floatingactionbutton:1.10.0' //GitHub开源FAB浮动Button }
只需在项目根目录下的build.gradle中添加上面几行代码,即可在编译时自动下载所需依赖包,这是我放弃Eclipse转用Studio最看重的一个方面,实在是太方便了。
1、启动闪屏页面实现
主流软件打开时都会有一个大概几秒钟的启动页面,此时后台可以进行网络初始化等操作。我的xml布局就不说了,只放了两个TextView显示两行文字,
实现思路很简单,通过开启线程打开新的页面,给线程设置等待时间就可以了。
看源码:
SplashActivity.java
[code]public class SplashActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_splash); //此处开启线程,等待两秒后执行,进入登录页面。 new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(2000); Intent mIntent = new Intent(SplashActivity.this, LoginActivity.class); startActivity(mIntent); //此处使用淡入淡出的切换动画 overridePendingTransition(R.anim.fade_in, R.anim.fade_out); finish(); } catch (InterruptedException e) { e.printStackTrace(); } } }).start(); } }
其中淡入淡出的xml资源如下(淡出相反)
R.anim.fade_in.xml
[code]<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android" android:fillAfter="true"> <alpha android:duration="1000"//持续时间1s android:fromAlpha="0.0"//开始透明度0% android:toAlpha="1.0"//结束透明度100% /> </set>
2、登录页面实现
登录页面主体使用ActionBar,有一个服务器设置ButtonEditText使用框架库,实现hint文字动态悬浮,获得焦点变色等效果。
CheckBox使用框架库,实现动画改变选中状态。
Button使用框架库,实现扁平化设计风格和点击ripple波纹效果。
activity_login.xml (只保留主要部分)
[code]<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <!-- 此处必须使用app命名空间,才可以改变自定义控件属性 --> <!-- 引用库中自定义EditText控件 --> <com.rengwuxian.materialedittext.MaterialEditText android:hint="Input your username" app:met_baseColor="@color/color_edit_text_unfocus" app:met_clearButton="true" app:met_floatingLabel="highlight" app:met_floatingLabelText="USERNAME" app:met_iconLeft="@drawable/ic_login_username" app:met_maxCharacters="10" app:met_primaryColor="@color/color_primary" app:met_singleLineEllipsis="true" /> <!-- 密码输入EditText,同上省略 --> <com.rengwuxian.materialedittext.MaterialEditText android:inputType="textPassword"/> <!-- 记住密码CheckBox控件 --> <com.rey.material.widget.CheckBox android:id="@+id/cb_login_rempass" style="@style/Material.Drawable.CheckBox" android:text="Rember Password" android:textColor="@color/color_primary" app:cbd_strokeColor="@color/color_primary" /> <!-- 登录Buttion --> <com.rey.material.widget.Button style="@style/Material.Drawable.Ripple.Touch.MatchView.Light" android:text="LOGIN" android:textColor="@color/carbon_white" app:rd_enable="true" /> </RelativeLayout>
登录页面Activity需要继承自com.blunderer.materialdesignlibrary.activities.Activity,然后重写需要重写的方法。
不要在onCreate中调用setContentView方法来设置布局资源
在重写方法getContentView中调用布局资源
需要单独封装AsyncHttpClient类,才能实现之后每次请求都保持登录状态,即设置cookie
使用SharePreferences来本地存储用户名和密码
创建用户信息类UserBean,通过get和set方法读写用户信息
创建服务器配置类ServerConfig来全局化配置服务器参数
通过重写onCreateOptionsMenu方法加载menu资源
通过重写onOptionsItemSelected设置menu监听
LoginActivity.java 实现源码
[code]public class LoginActivity extends com.blunderer.materialdesignlibrary.activities.Activity{ private Button btn_login; //其他控件省略 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //此处不写setContentView(R.layout.activity_login) //布局加载在重写的getContentView方法中 init();//初始化数据 isSavedPassword();//自动填充密码 setOnclickListener();//按钮监听 } /* 初始化 */ protected void init() { //绑定控件,其他省略 et_username =(MaterialEditText) findViewById(R.id.et_login_username); } /* 自动填充密码 */ protected void isSavedPassword() { //使用SharePreferences来存储用户名和密码 SharedPreferences sharedPreferences = getSharedPreferences("UserLogin", MODE_PRIVATE); String username = sharedPreferences.getString("username", ""); String password = sharedPreferences.getString("password", ""); if (!(username.equals("")) && !(password.equals(""))) { cb_rempass.setChecked(true); } et_password.setText(password); et_username.setText(username); } /* 登陆按钮监听 */ protected void setOnclickListener() { btn_login.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //从服务器配置类中取出配置参数 ServerConfig server = new ServerConfig(); String flag = server.getFLAG(); String url = server.getURL_USER_LOGIN(); String username = et_username.getText().toString(); String password = et_password.getText().toString(); //判断输入是否为空 if (!isEmptyInput(username, password)) { doSavePassword(username, password); //执行登录 doLogin(url, flag, username, password); } } }); } /* 空输入判断 */ protected boolean isEmptyInput(String username, String password) { //省略不写 } /* 记住密码 */ protected void doSavePassword(String username, String password) { SharedPreferences sharedPreferences = getSharedPreferences("UserLogin", MODE_PRIVATE); SharedPreferences.Editor editor = sharedPreferences.edit(); //如果CheckBox选中的话则存入帐号密码,否则存入空 if (cb_rempass.isChecked()) { editor.putString("username", username); editor.putString("password", password); editor.commit(); } else { editor.putString("username", ""); editor.putString("password", ""); editor.commit(); } } /* 执行登录 */ protected void doLogin(String url, String flag, String username, String password) { // 实例化client对象,我把AsyncHttpClient另外封装为一个类,增加setCookie功能 AsyncHttpClient client = new FinalAsyncHttpClient().getAsyncHttpClient(); //不知道为什么,在登录前就要执行保存cookie,否则会失败 saveCookie(client); // 设置请求参数 RequestParams params = new RequestParams(); params.put("flag", flag); params.put("username", username); params.put("password", password); // 执行post请求 client.post(url, params, new AsyncHttpResponseHandler() { //登录成功 @Override public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) { try { JSONObject jo = new JSONObject(new String(responseBody)); if (jo.getString("result").equals("登陆成功")) { // 存储登录成功cookie CookieUtils.setCookies(getCookie()); // 存储用户信息 saveUserInfoByString(new String(responseBody)); // 跳转至主页面 toMainActivity(); } } catch (Exception e) { e.printStackTrace(); } } //登录失败 @Override public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) { Toast.makeText(getApplicationContext(), error.toString(), Toast.LENGTH_SHORT).show(); System.out.println("login登录失败:" + error.toString()); } }); } /* 用户信息存储 */ protected void saveUserInfoByString(final String userJson) { try { //实例化用户信息类UserBean,用于存储用户各项信息,此处省略 UserBean ub = new UserBean(); JSONObject user = new JSONObject(userJson); ub.setUserId(user.getString("userId")); } catch (JSONException e) { e.printStackTrace(); } } /* 跳转主页 */ protected void toMainActivity() { Intent mIntent = new Intent(LoginActivity.this, MainActivity.class); this.startActivity(mIntent); this.finish(); } /* 保存cookie */ protected void saveCookie(AsyncHttpClient client) { PersistentCookieStore cookieStore = new PersistentCookieStore(this); client.setCookieStore(cookieStore); } /* 得到cookie */ protected List<Cookie> getCookie() { PersistentCookieStore cookieStore = new PersistentCookieStore(this); List<Cookie> cookies = cookieStore.getCookies(); return cookies; } //此处返回布局资源id @Override protected int getContentView() { return R.layout.activity_login; } //允许ActionBar阴影 @Override protected boolean enableActionBarShadow() { return true; } //ActionBarHandler @Override protected ActionBarHandler getActionBarHandler() { return new ActionBarDefaultHandler(this); } //设置Option菜单 @Override public boolean onCreateOptionsMenu(Menu menu) { //此处调用menu资源 getMenuInflater().inflate(R.menu.menu_login, menu); return super.onCreateOptionsMenu(menu); } //设置menu菜单点击事件 @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { //服务器设置按钮 case R.id.btn_login_server: Intent intent = new Intent(LoginActivity.this, ServerSettingActivity.class); startActivity(intent); return true; default: return super.onOptionsItemSelected(item); } } }
用户信息类示例 UserBean.java
[code]public final class UserBean { private static String userId;//用户信息变量 //get方法 public String getUserId() { return userId; } //set方法 public void setUserId(String userId) { UserBean.userId = userId; } }
AsyncHttpClient封装类
[code]public class FinalAsyncHttpClient { private AsyncHttpClient client; /* 构造方法 */ public FinalAsyncHttpClient() { client = new AsyncHttpClient();//实例化对象 client.setTimeout(5);//设置超时 // 获取cookie列表 if (CookieUtils.getCookies() != null) { BasicCookieStore bcs = new BasicCookieStore(); bcs.addCookies(CookieUtils.getCookies().toArray( new Cookie[CookieUtils.getCookies().size()])); client.setCookieStore(bcs); } } /* 得到client对象方法 */ public AsyncHttpClient getAsyncHttpClient() { return this.client; } }
cookie处理类
[code]public class CookieUtils { private static List<Cookie> cookies; /* 返回cookies列表 */ public static List<Cookie> getCookies() { return cookies != null ? cookies : new ArrayList<Cookie>(); } /* 设置cookies列表 */ public static void setCookies(List<Cookie> cookies) { CookieUtils.cookies = cookies; } }
3、主页面实现
主页面继承自com.blunderer.materialdesignlibrary.activities.ViewPagerWithTabsActivity重写必须重写的方法
在getViewPagerHandler方法中加载Fragment对象
expandTabs方法中,true:扩展Tab占满屏幕宽,false相反
defaultViewPagerPageSelectedPosition方法设置默认选择tab
onCreateOptionsMenu方法加载menu资源
onOptionsItemSelected方法设置menu点击事件
在点击注销按钮时创建一个dialog,此处需要注意
AlertDialog.Builder builder = new AlertDialog.Builder(this);
此时参数Context可以传入this,因为是在Activity类中;
若在Fragment中,则不能使用this或是getApplicationContext( ),要使用getActivity( ),否则报错
MainActivity.java
[code]public class MainActivity extends ViewPagerWithTabsActivity { @Override protected boolean enableActionBarShadow() { return true;//允许阴影 } @Override public ViewPagerHandler getViewPagerHandler() { //通过ViewPagerHandler添加Fragment页面 ViewPagerHandler handler = new ViewPagerHandler(this); handler.addPage("页面标题一", TalkCheckFragment.newInstance()); handler.addPage("页面标题二", UserInfoFragment.newInstance()); handler.addPage("页面标题三", TalkLookFragment.newInstance()); return handler; } @Override public boolean expandTabs() { return true;//是否让Tab平均占满屏幕宽度 } @Override public int defaultViewPagerPageSelectedPosition() { return 1;//进入页面时默认打开的Tab,从0开始 } @Override protected ActionBarHandler getActionBarHandler() { return new ActionBarDefaultHandler(this); } @Override public boolean onCreateOptionsMenu(Menu menu) { //加载menu资源 getMenuInflater().inflate(R.menu.menu_main, menu); return super.onCreateOptionsMenu(menu); } //menu中注销按钮点击事件 @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.btn_main_menu: //弹出注销提示框 AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle("提示"); builder.setMessage("确认要注销当前用户吗?"); builder.setPositiveButton("Confirm", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); Intent intent = new Intent(MainActivity.this, LoginActivity.class); startActivity(intent); finish(); } }); builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); } }); builder.create().show(); return true; default: return super.onOptionsItemSelected(item); } } }
4、谈话列表页面Fragment实现
谈话列表页面使用RecyclerView+CardView组合方式,实现灵活多变的卡片式列表布局,并且根据数据内容而显示不同的效果,以及卡片点击事件监听。首先看看布局资源
fragment_talk_list.xml
[code]<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:fab="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <FrameLayout android:id="@+id/frame" android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.v7.widget.RecyclerView android:id="@+id/rv_main_list" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity" /> </FrameLayout> <!-- 悬浮按钮控件 --> <com.getbase.floatingactionbutton.FloatingActionButton android:id="@+id/fab_list_newTalk" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_above="@id/frame" android:layout_alignParentBottom="true" android:layout_alignParentRight="true" android:layout_marginBottom="16dp" fab:fab_colorNormal="@color/color_primary" fab:fab_colorPressed="@color/color_primary_dark" fab:fab_icon="@drawable/ic_fab_star" /> </RelativeLayout>
下面看Fragment实现源码
继承自android.support.v4.app.Fragment
onCreateView方法用于加载布局资源
newInstance方法用于获取Fragment实例
调用jsonArrayToMapList方法将服务端返回JsonArray转存为List< Map >对象
bindToListView方法把数据绑定到CardView中显示
[code]public class TalkCheckFragment extends Fragment { private RecyclerView mRecyclerView; private TalkListAdapter mTalkListAdapter; private FloatingActionButton fab_createTalk; /* 得到Fragment对象实例 */ public static TalkCheckFragment newInstance() { TalkCheckFragment fragment = new TalkCheckFragment(); return fragment; } /* 获取谈话列表 */ private void getTalkList(String url, String userId) { AsyncHttpClient client = new FinalAsyncHttpClient().getAsyncHttpClient(); RequestParams params = new RequestParams(); params.put("userid", userId); params.put("flag", "2"); client.get(url, params, new AsyncHttpResponseHandler() { @Override public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) { //获取服务器资源成功后转换JsonArray数据 List<HashMap<String, String>> data = jsonArrayToMapList(new String(responseBody)); bindToListView(data); } /* 将JsonArray转存为List<Map> */ private List<HashMap<String, String>> jsonArrayToMapList(String result) { List<HashMap<String, String>> data = new ArrayList<>(); try { JSONArray ja = new JSONArray(result); for (int i = 0; i < ja.length(); i++) { HashMap<String, String> talk = new HashMap<>(); JSONObject jo = ja.getJSONObject(i); Iterator<String> it = jo.keys(); while (it.hasNext()) { String key = String.valueOf(it.next()); String value = (String) jo.get(key); talk.put(key, value); } data.add(talk); } } return data; } /* 绑定数据集到列表视图 */ private void bindToListView(List<HashMap<String, String>> data) { //给RecyclerView设置线性布局管理器 mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity())); //设置默认item属性动画 mRecyclerView.setItemAnimator(new DefaultItemAnimator()); mRecyclerView.setHasFixedSize(true); //实例化自定义适配器 mTalkListAdapter = new TalkListAdapter(getActivity(), data); //设置卡片视图点击事件监听器 //OnCardViewClickListener为抽象接口,需要实现onItemClick方法 mTalkListAdapter.setOnCardViewClickListener(new TalkListAdapter.OnCardViewClickListener() { @Override public void onItemClick(View view, Map<String, String> data) { String talkId = data.get("id"); System.out.println("talkid="+talkId); } }); //绑定适配器 mRecyclerView.setAdapter(mTalkListAdapter); } /* FAB悬浮按钮监听 */ private void setFabListener() { fab_createTalk.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //弹出新建谈话提示框 AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); builder.setTitle("提示"); builder.setMessage("确定要新建谈话吗?"); builder.setPositiveButton("我要新建谈话", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); Intent intent = new Intent(getActivity(), NewTalkActivity.class); startActivity(intent); } }); builder.setNegativeButton("取消", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); } }); builder.create().show(); } }); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { //得到谈话列表Fragment视图对象 View view = inflater.inflate(R.layout.fragment_talk_list, container, false); //根据View对象绑定RecyclerView控件 mRecyclerView = (RecyclerView) view.findViewById(R.id.rv_main_list); //设置FAB悬浮按钮监听 fab_createTalk = (FloatingActionButton) view.findViewById(R.id.fab_list_newTalk); setFabListener(); //请求服务器获取谈话列表 String url = new ServerConfig().getURL_TALK_LIST(); String userId = new UserBean().getUserId(); getTalkList(url, userId); //返回视图 return view; } }
5、RecyclerView自定义Adapter实现
RecyclerView并没有ListView的onItemClickListener方法, 需要我们自己写需要自己写ViewHolder类并且继承自RecyclerView.ViewHolder
需要自己写卡片点击事件监听器接口OnCardViewClickListener
onCreateViewHolder方法中加载CardView布局资源
该Adapter需要继承RecyclerView.Adapter< TalkListAdapter.ViewHolder >,泛型需要指定为自定义的ViewHolder类
该Adapter需要实现View.OnClickListener接口,在onClick方法中调用自定义的卡片点击监听器接口的onItemClick方法。
[code]public class TalkListAdapter extends RecyclerView.Adapter<TalkListAdapter.ViewHolder> implements View.OnClickListener { private List<HashMap<String, String>> mDataSet;//数据集 private Context mContext;//上下文对象 private OnCardViewClickListener mCardViewListener = null;//自定义卡片点击监听器 /* 构造方法,在实例化适配器时传入上下文和数据集 */ public TalkListAdapter(Context context, List<HashMap<String, String>> dataSet) { this.mContext = context; this.mDataSet = dataSet; } /* 创建卡片视图,即单个数据列表项Item */ @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_card_view, parent, false); //实例化viewHolder对象,传入卡片视图View对象 ViewHolder viewHolder = new ViewHolder(v); //设置卡片点击监听 v.setOnClickListener(this); return viewHolder; } /* 绑定ViewHolder,将数据显示到对应控件上 */ @Override public void onBindViewHolder(ViewHolder holder, int position) { //根据position取出数据集中数据,并绑定至ViewHolder中对应控件 HashMap<String, String> item = mDataSet.get(position); //取出数据并显示在控件中 holder.tv_title.setText(item.get("talktitle")); //设置Tag标签用于点击事件得到数据 holder.itemView.setTag(item); } /* 得到数据集长度 */ @Override public int getItemCount() { return mDataSet == null ? 0 : mDataSet.size(); } /* 实现OnClick接口方法 */ @Override public void onClick(View v) { //当卡片视图监听器不为null时,则执行监听器接口方法 if (mCardViewListener != null) { //通过v.getTag得到数据,强转为Map类型 mCardViewListener.onItemClick(v, (Map<String, String>) v.getTag()); } } /* 绑定卡片视图点击事件监听器 */ public void setOnCardViewClickListener(OnCardViewClickListener listener) { this.mCardViewListener = listener; } /* 必须实现自定义ViewHolder,继承自RecyclerView.ViewHolder */ public static class ViewHolder extends RecyclerView.ViewHolder { //成员变量 public TextView tv_title, tv_state, tv_person, tv_org, tv_date; public View iv_header; //构造方法,传入View对象,绑定控件id public ViewHolder(View v) { super(v); tv_title = (TextView) v.findViewById(R.id.tv_list_title); tv_state = (TextView) v.findViewById(R.id.tv_list_state); tv_date = (TextView) v.findViewById(R.id.tv_list_date); tv_org = (TextView) v.findViewById(R.id.tv_list_org); tv_person = (TextView) v.findViewById(R.id.tv_list_person); iv_header = v.findViewById(R.id.img_card_header); } } /* 卡片点击事件监听接口 */ public interface OnCardViewClickListener { void onItemClick(View view, Map<String, String> data); } }
至此,该项目的主要功能基本就实现了,一些比较简单的就没写出,主要是给自己的项目练习做个总结,方便以后有需要的时候回顾,也希望能让更多初学者能从中多少获得一些收获,共同进步。
再次表达一下对Material Design的喜爱之情,真的是太棒了,看看那些大神们封装的各种控件库,真的是美的不行不行的,完全秒杀iPhone的界面设计了我觉得。
有问题可私信我,有共同学习的小伙伴联系我,需要源码也可以找我。QQ12547345
相关文章推荐
- Android下各个按键对应的key code
- Android播放器显示:surfaceview invalid token (identity=473)
- Adnroid Ratingbar 动态设置Star iamge
- Android 开发环境搭建
- 打印Android HAL层堆栈
- 判断root
- Android RecyclerView的使用学习
- Android中的内存储、外存储概念、文件操作与PC端的有些不同
- Android系统签名文件
- android studio引入最新版银联支付功能
- Android - 手机淘宝启动页(Splash)是如何实现的?
- android利用draglayout实现菜单栏顶部悬浮效果
- 四、Android.mk之编译生成可执行文件
- Android-Anim-Playground
- Android 布局优化
- Android中将布局文件/View添加至窗口过程分析 ---- 从setContentView()谈起
- Android 笔记:2015.09.23
- 详解Android中AsyncTask的使用
- android 播放gif
- Android中获取当前位置的三种方式