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 练习之路 的主要内容,如果未能解决你的问题,请参考以下文章

android 练习之路

android 练习之路

android 练习之路

android 练习之路

屏幕旋转后Android片段重叠

Android代码片段