android 练习之路
Posted Qunter
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了android 练习之路 相关的知识,希望对你有一定的参考价值。
项目的github地址:https://github.com/Qunter/SearchAndCall
------------------------------------------------------------------------
时隔三四天吧,把第二个模块——周边活动做了个七七八八,暂时就先达到这个效果,过段时间再改
这里要说一下,之前的工程里,我有的时候把详情这个单词(detail)写成了错误的dateil,目前工程里已经全部改正过来了,算是给自己提个醒吧,太粗心了......囧
PS:其实是这几天要参加竞赛了,先把效果做个大概,等把作品提交完了之后再慢慢优化和美化吧
老样子,先上个gif效果图
这里先从基类说起,可以看到登录界面是沉浸式的,效果比较好,但是在后面的创建活动页面,如果用沉浸式的话体验特别差,但是因为沉浸式是写在基类里面的,所以我再封装一次,首先建一个标志,再设置一个方法以更改这个标志,在子类里使用这个方法来设置标志,再通过判断标志来决定是否执行沉浸式的代码
PS:沉浸式我之前的英文拼写有误,我写的是initstate,受了以前学习过程中其他博主的误导,可能我没理解他方法中的state是什么意思,我窃以为是沉浸式,其实不是的,所以方法改了个名字
这是改正后的方法
private void initImmersive () { getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){//4.4 全透明状态栏 getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); } if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {//5.0 全透明实现 Window window = getWindow(); window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE); window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); window.setStatusBarColor(Color.TRANSPARENT);//calculateStatusColor(Color.WHITE, (int) alphaValue) } }
然后是之前说的,设置一个标志(默认不沉浸式)
//是否设置沉浸式 private boolean IfImmersive = false;
/** * 设置是否沉浸式 在子类中super调用 */ public void setIfImmersive(boolean IfImmersive){ this.IfImmersive = IfImmersive; }
最后通过判断这个标志来得知是否设置该页面沉浸式
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); initVariablesAndService(); initViews(savedInstanceState); if(IfImmersive){ initImmersive(); } }
基类就改到这,下面一步一步来,可以从gif里面看到,我的周边活动模块是分了两个fragment的,一个是周边活动,一个是我的活动,需要用viewpager实现
activity_event_info_fragm.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.design.widget.TabLayout android:id="@+id/eventTabLayout" android:layout_width="match_parent" android:layout_height="45dp" app:tabIndicatorColor="@android:color/black"/> <android.support.v4.view.ViewPager android:id="@+id/eventViewPaper" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1"/> </LinearLayout>
写到这我想起来了,之前学校的相关页面中,有些id我也改动了一下,不过其实问题不大,主要是为了代码规范,这里就不列出了
那么再写一个类文件与之对应
EventInfoFragmActivity.java
public class EventInfoFragmActivity extends Fragment { public static EventInfoFragmActivity newInstance() { return new EventInfoFragmActivity(); } @Nullable @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.activity_event_info_fragm,container,false); //Fragment+ViewPager+FragmentViewPager组合的使用 ViewPager viewPager = (ViewPager) view.findViewById(R.id.eventViewPaper); EventPagerAdapter adapter = new EventPagerAdapter(getActivity().getSupportFragmentManager(), getContext()); viewPager.setAdapter(adapter); //TabLayout TabLayout tabLayout = (TabLayout) view.findViewById(R.id.eventTabLayout); tabLayout.setupWithViewPager(viewPager); return view; } }
viewpager是需要设置个adapter的,所以我们再建一个adapter
EventPagerAdapter.java
public class EventPagerAdapter extends FragmentPagerAdapter { public final int COUNT = 2; private String[] titles = new String[]{"周边活动", "我的活动"}; private Context context; public EventPagerAdapter(FragmentManager fm, Context context) { super(fm); this.context = context; } @Override public Fragment getItem(int position) { return EventPageFragment.newInstance(position); } @Override public int getCount() { return COUNT; } @Override public CharSequence getPageTitle(int position) { return titles[position]; } }
代码比较简单,一眼就看得懂
之后,既然是通过adapter来创建并且添加页面,那么创建的这个页面就需要写一下了,先写个xml,其实内容很简单,就是一个recycleView
activity_event_list.xml
<?xml version="1.0" encoding="utf-8"?> <android.support.v4.widget.SwipeRefreshLayout android:id="@+id/swipe_refresh_event" xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.v7.widget.RecyclerView android:id="@+id/recycler_event" android:layout_width="match_parent" android:layout_height="match_parent" android:overScrollMode="never" android:scrollbars="vertical" /> </android.support.v4.widget.SwipeRefreshLayout>
得,之后就是对应的Activity了
EventPageFragment.java
public class EventPageFragment extends Fragment { public static final String EVENTMODE = "eventmode"; private int eventmode = 0; private SwipeRefreshLayout eventSwipeRefreshLayout; private EventInfoListAdapter adapter; private List<EventInfo> aroundEventData, mineEventData; private RecyclerView eventRecyclerView; private boolean ifFirstInitData=true; private final int GETAROUNDEVENTDATA=0x00,GETMINEEVENTDATA=0x01,REFRESHAROUNDEVENT=0x02,REFRESHMINEEVENT=0x03,REFRESH=0x04; private Handler handler = new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what){ case GETAROUNDEVENTDATA: getAroundEventData(); break; case GETMINEEVENTDATA: getMineEventData(); break; case REFRESHAROUNDEVENT: loadAroundEventRecycleView(); if(ifFirstInitData){ ifFirstInitData = false; }else{ handler.sendEmptyMessage(REFRESH); } break; case REFRESHMINEEVENT: loadMineEventRecycleView(); if(ifFirstInitData){ ifFirstInitData = false; }else{ handler.sendEmptyMessage(REFRESH); } break; case REFRESH: adapter.notifyDataSetChanged(); Toast.makeText(getContext(),"刷新成功",Toast.LENGTH_SHORT).show(); eventSwipeRefreshLayout.setRefreshing(false); break; } } }; public static EventPageFragment newInstance(int eventmode) { Bundle args = new Bundle(); args.putInt(EVENTMODE, eventmode); EventPageFragment fragment = new EventPageFragment(); fragment.setArguments(args); return fragment; } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); eventmode = getArguments().getInt(EVENTMODE); } @Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.activity_event_list,container,false); eventSwipeRefreshLayout = (SwipeRefreshLayout) view.findViewById(R.id.swipe_refresh_event); eventSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { @Override public void onRefresh() { initData(); } }); eventRecyclerView = (RecyclerView) view.findViewById(R.id.recycler_event); LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity()); eventRecyclerView.setLayoutManager(layoutManager); initData(); return view; } /** * 根据eventmode判断是周边活动页还是我的活动页并发送相应的msg以获取对应页面所需数据 */ private void initData(){ if(eventmode==0){ handler.sendEmptyMessage(GETAROUNDEVENTDATA); }else if (eventmode==1){ handler.sendEmptyMessage(GETMINEEVENTDATA); } } /** * 查询周边活动 */ private void getAroundEventData(){ BmobQuery<EventInfo> aroundEventQuery = new BmobQuery<EventInfo>(); //执行查询方法 aroundEventQuery.findObjects(new FindListener<EventInfo>() { @Override public void done(List<EventInfo> object, BmobException e) { if(e==null){ aroundEventData = object; handler.sendEmptyMessage(REFRESHAROUNDEVENT); }else{ } } }); } /** * 查询我的活动 */ private void getMineEventData(){ BmobQuery<EventInfo> aroundEventQuery = new BmobQuery<EventInfo>(); //执行查询方法 aroundEventQuery.findObjects(new FindListener<EventInfo>() { @Override public void done(List<EventInfo> object, BmobException e) { if(e==null){ mineEventData = object; handler.sendEmptyMessage(REFRESHMINEEVENT); }else{ } } }); } /** * 加载周边活动数据至RecycleView */ private void loadAroundEventRecycleView(){ adapter = new EventInfoListAdapter(getContext(),aroundEventData,eventRecyclerView); adapter.setOnItemClickListener(new EventInfoListAdapter.OnItemClickListener() { @Override public void onItemClick(View view, int position) { Intent intent = new Intent(getContext(),EventDetailActivity.class); intent.putExtra("eventInfo",aroundEventData.get(position)); startActivity(intent); } }); eventRecyclerView.setAdapter(adapter); } /** * 加载我的活动数据至RecycleView */ private void loadMineEventRecycleView(){ adapter = new EventInfoListAdapter(getContext(),mineEventData,eventRecyclerView); adapter.setOnItemClickListener(new EventInfoListAdapter.OnItemClickListener() { @Override public void onItemClick(View view, int position) { Intent intent = new Intent(getContext(),EventDetailActivity.class); intent.putExtra("eventInfo",mineEventData.get(position)); startActivity(intent); } }); eventRecyclerView.setAdapter(adapter); } }
代码有那么点长,注释其实还是基本讲清楚了,不过逻辑还是说一下吧
首先创建这个fragment的时候用newInstance来创建,写一个newInstance,创建的时候(在adapter里创建,会传入position)传入一个参数,这里用的是int,以便知道具体是哪个页面,在上述代码中,0代表的是周边活动fragment,1则是我的活动
当然这个int很难直接存进去(不能直接intent传入,因为Fragment和Activity不一样),所以在newInstance的时候传入一个Bundle,Bundle里存入键值对,然后new的时候通过键取出值然后赋值给eventmode,创建fragment之后,通过eventmode来判断是哪个fragment,通过发送不同的msg来调用不同的方法获取数据以填充进去形成不同的fragment,简而言之,类似构造器设计模式
之后就不用多说了,老一套,创建个adpter,给recycleview填充数据,并且设置点击事件,点击item之后弹出详情页面,页面左上角的剪头是返回按钮,用Imageview实现
EventInfoListAdapter.java
public class EventInfoListAdapter extends RecyclerView.Adapter<EventInfoListAdapter.ViewHolder>{ private List<EventInfo> schoolInfoList; private Context context; private RecyclerView recyclerView; private OnItemClickListener onItemClickListener; static class ViewHolder extends RecyclerView.ViewHolder{ TextView eventTitleTv,eventTimeStartTv,eventTimeEndTv; public ViewHolder(View view){ super(view); eventTitleTv = (TextView) view.findViewById(R.id.event_title); eventTimeStartTv = (TextView) view.findViewById(R.id.event_time_start); eventTimeEndTv = (TextView) view.findViewById(R.id.event_time_end); } } public EventInfoListAdapter(Context context,List<EventInfo> list,RecyclerView recyclerView){ this.context = context; this.schoolInfoList = list; this.recyclerView = recyclerView; } @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_event_info,parent,false); ViewHolder holder = new ViewHolder(view); return holder; } @Override public void onBindViewHolder(final ViewHolder holder, int position) { holder.setIsRecyclable(false); EventInfo eventInfo = schoolInfoList.get(position); holder.eventTitleTv.setText(eventInfo.getEventTitle()); holder.eventTimeStartTv.setText("活动开始时间为: "+eventInfo.getEventStartDate().getDate()); holder.eventTimeEndTv.setText("活动结束时间为: "+eventInfo.getEventEndDate().getDate()); if(onItemClickListener != null){ //为ItemView设置监听器 holder.itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { int position = holder.getLayoutPosition(); onItemClickListener.onItemClick(holder.itemView,position); } }); } } @Override public int getItemCount() { return schoolInfoList.size(); } /** * 点击事件接口 */ public interface OnItemClickListener{ void onItemClick(View view,int position); } /** * 设置点击事件方法 */ public void setOnItemClickListener(OnItemClickListener onItemClickListener){ this.onItemClickListener = onItemClickListener; } }
和之前学校资讯列表同理,并且更为简单,就不再赘述了
然后是点击之后弹出的详情页面
activity_event_detail.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.design.widget.AppBarLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" app:popupTheme="@style/ThemeOverlay.AppCompat.Light" app:theme="@style/Theme.AppCompat.Light"> <ImageView android:id="@+id/event_detail_backBtn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="left" android:src="@drawable/ic_arrow_back_black_36dp"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:text="活动详情" android:textSize="22sp" android:textColor="#dd000000" /> </android.support.v7.widget.Toolbar> </android.support.design.widget.AppBarLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:padding="20dp"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="活动标题:" android:textSize="20sp"/> <TextView android:id="@+id/event_detail_titleTv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="16sp"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="活动内容:" android:textSize="20sp"/> <TextView android:id="@+id/event_detail_contentTv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="16sp"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="活动开始时间:" android:textSize="20sp"/> <TextView android:id="@+id/event_detail_timeStartTv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="16sp"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="活动结束时间:" android:textSize="20sp"/> <TextView android:id="@+id/event_detail_timeEndTv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="16sp"/> </LinearLayout> </LinearLayout>
以及对应的Activity
EventDetailActivity.java
public class EventDetailActivity extends BaseActivity { private EventInfo eventInfo; private TextView eventDetailTitleTv, eventDetailContentTv, eventDetailTimeStartTv, eventDetailTimeEndTv; private ImageView eventDetailBackBtn; @Override protected void initVariablesAndService() { eventInfo = (EventInfo) getIntent().getExtras().get("eventInfo"); } @Override protected void initViews(Bundle savedInstanceState) { setContentView(R.layout.activity_event_detail); eventDetailTitleTv = (TextView) findViewById(R.id.event_detail_titleTv); eventDetailContentTv = (TextView) findViewById(R.id.event_detail_contentTv); eventDetailTimeStartTv = (TextView) findViewById(R.id.event_detail_timeStartTv); eventDetailTimeEndTv = (TextView) findViewById(R.id.event_detail_timeEndTv); eventDetailBackBtn = (ImageView) findViewById(R.id.event_detail_backBtn); eventDetailTitleTv.setText(eventInfo.getEventTitle()); eventDetailContentTv.setText(eventInfo.getEventContent()); eventDetailTimeStartTv.setText(eventInfo.getEventStartDate().getDate()); eventDetailTimeEndTv.setText(eventInfo.getEventEndDate().getDate()); eventDetailBackBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { finish(); } }); } }
因为填充内容需要把对应的数据传进来,这里是通过intent传参,之前在adapter里设置了intent的Extras,这里只需要get之后强转一下类型就可使用
最后就是活动创建页面了,篇幅有点长,这里还是截个图吧
通过点击红色箭头标记的这个“+”,可以打开活动创建页面
两个Edittext和底下三个Button自不必说,这里要提到的是中间这个滑动选择时间的控件,这是自定义控件,是我从该项目前身项目中提取出来的一个自定义view,当然,这个view也是参考了其他人的作品,截取出来修改而成,具体在哪,时间过久了真是不记得了,过几天忙完了我会发个链接把代码贴上来,这里就不解释这个自定义view了,只说怎么用就行了
需要定义一个xml作为这个自定义view的样式
timepicker.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#ffffff" android:orientation="vertical" > <FrameLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingLeft="10dp" android:paddingRight="10dp" > <LinearLayout android:id="@+id/timePicker1" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" > <com.qunter.searchcall.engine.timePicket.WheelView android:id="@+id/year" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" /> <com.qunter.searchcall.engine.timePicket.WheelView android:id="@+id/month" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" /> <com.qunter.searchcall.engine.timePicket.WheelView android:id="@+id/day" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" /> <com.qunter.searchcall.engine.timePicket.WheelView android:id="@+id/hour" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" /> <com.qunter.searchcall.engine.timePicket.WheelView android:id="@+id/min" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" /> </LinearLayout> <ImageView android:layout_width="match_parent" android:layout_height="22dp" android:layout_gravity="center_vertical" android:background="@drawable/timepicket_wheel_val" /> </FrameLayout> </LinearLayout>
然后是背景和边框了,在drawable里建三个xml,一个是单独一个轮的背景,一个是整体背景,一个是整体边框
timechoose_bg.xml
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" > <solid android:color="#00000000" /> <stroke android:width="2px" android:color="#d4d4d4" /> <corners android:bottomLeftRadius="10dp" android:bottomRightRadius="10dp" android:topLeftRadius="10dp" android:topRightRadius="10dp" /> <padding android:bottom="0dp" android:left="0dp" android:right="0dp" android:top="0dp" /> </shape>
timepicket_wheel_bg.xml
<?xml version="1.0" encoding="utf-8"?> <layer-list xmlns:android="http://schemas.android.com/apk/res/android" > <item> <shape android:shape="rectangle" > <gradient android:angle="0" android:centerColor="#FFFFFFFF" android:endColor="#FFFFFFFF" and以上是关于android 练习之路 的主要内容,如果未能解决你的问题,请参考以下文章