《移动项目实践》实验报告——Android高级控件

Posted Starzkg

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《移动项目实践》实验报告——Android高级控件相关的知识,希望对你有一定的参考价值。

实验目的

1、熟悉App开发常用的一些高级控件及相关工具,主要包括日期时间控件的用法、列表类视图及其适配器的用法、翻页类视图及其适配器的用法、碎片及其适配器的用法等;
2、熟悉四大组件之一广播Broadcast的基本概念与常见用法;

实验内容

1、万年历:最简单的时间功能仅能查看当前的年月日、时分秒,若要拓展它的功能,则可由日历变月历,在年月日之外补充星期几,再添加节假日描述。进一步升级扩展,由月历变年历,分别按公历与农历纪年,便成了万年历;
万年历的界面效果

2、日程表(日程提醒采用手机震动的方式):日程表不但支持基本的日历信息展示,而且支持用户设定每天的日程安排,还支持日程提醒时间。

日程表的主页面

日程安排/详情页面

实验过程(实验的设计思路、关键源代码等)

源代码:https://gitee.com/shentuzhigang/mini-project/tree/master/android-calendar

package io.shentuzhigang.demo.calendar

import android.annotation.SuppressLint
import android.graphics.Color
import android.os.Bundle
import android.util.TypedValue
import android.view.View
import android.widget.LinearLayout
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.viewpager.widget.PagerTabStrip
import androidx.viewpager.widget.ViewPager
import io.shentuzhigang.demo.calendar.util.DateUtil
import io.shentuzhigang.demo.calendar.widget.MonthPicker
import io.shentuzhigang.demo.calendar.adapter.CalendarPagerAdapter
@SuppressLint("SetTextI18n")
class CalendarActivity : AppCompatActivity(), View.OnClickListener {
    private var ll_calendar_main // 声明一个万年历区域的线性布局对象
            : LinearLayout? = null
    private var ll_month_select // 声明一个月份选择区域的线性布局对象
            : LinearLayout? = null
    private var mp_month // 声明一个月份选择器对象
            : MonthPicker? = null
    private var vp_calendar // 声明一个翻页视图对象
            : ViewPager? = null
    private var tv_calendar // 声明一个选中年份的文本视图对象
            : TextView? = null
    private var isShowSelect = false // 是否显示月份选择器
    private var mSelectedYear = 2000 // 当前选中的年份
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_calendar)
        ll_calendar_main = findViewById(R.id.ll_calendar_main)
        ll_month_select = findViewById(R.id.ll_month_select)
        // 从布局文件中获取名叫mp_month的月份选择器
        mp_month = findViewById<MonthPicker>(R.id.mp_month)
        // 从布局文件中获取名叫pts_calendar的翻页标题栏
        findViewById<View>(R.id.btn_ok).setOnClickListener(this)
        val pts_calendar = findViewById<PagerTabStrip>(R.id.pts_calendar)
        pts_calendar.setTextSize(TypedValue.COMPLEX_UNIT_SP, 17f)
        pts_calendar.setTextColor(Color.BLACK)
        // 从布局文件中获取名叫vp_calendar的翻页视图
        vp_calendar = findViewById(R.id.vp_calendar)
        tv_calendar = findViewById(R.id.tv_calendar)
        with(tv_calendar){
            this?.setOnClickListener(this@CalendarActivity)
        }
        // 万年历默认显示当前年月的月历
        showCalendar(DateUtil.nowYear, DateUtil.nowMonth)
    }

    // 显示指定年月的万年历
    private fun showCalendar(year: Int, month: Int) {
        // 如果指定年份不是上次选中的年份,则需重新构建该年份的年历
        if (year != mSelectedYear) {
            tv_calendar!!.text = year.toString() + "年"
            // 构建一个指定年份的年历翻页适配器
            val adapter = CalendarPagerAdapter(supportFragmentManager, year)
            // 给vp_calendar设置年历翻页适配器
            vp_calendar!!.adapter = adapter
            mSelectedYear = year
        }
        // 设置vp_calendar默认显示指定月份的月历页
        vp_calendar!!.currentItem = month - 1
    }

    override fun onClick(v: View) {
        if (v.id == R.id.tv_calendar) { // 点击了年份文本
            // 重新选择万年历的年月
            resetPage()
        } else if (v.id == R.id.btn_ok) { // 点击了确定按钮
            // 根据月份选择器上设定的年月,刷新万年历的显示界面
            showCalendar(mp_month!!.getYear(), mp_month!!.getMonth() + 1)
            resetPage()
        }
    }

    // 重置页面。在显示万年历主页面和显示月份选择器之间切换
    private fun resetPage() {
        isShowSelect = !isShowSelect
        ll_calendar_main!!.visibility = if (isShowSelect) View.GONE else View.VISIBLE
        ll_month_select!!.visibility = if (isShowSelect) View.VISIBLE else View.GONE
    }

    companion object {
        private const val TAG = "CalendarActivity"
    }
}
package io.shentuzhigang.demo.calendar

import android.content.*
import android.graphics.Color
import android.os.*
import android.util.Log
import android.util.TypedValue
import android.widget.LinearLayout
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.localbroadcastmanager.content.LocalBroadcastManager
import androidx.viewpager.widget.PagerTabStrip
import androidx.viewpager.widget.ViewPager
import androidx.viewpager.widget.ViewPager.OnPageChangeListener
import io.shentuzhigang.demo.calendar.adapter.SchedulePagerAdapter
import io.shentuzhigang.demo.calendar.calendar.SpecialCalendar
import io.shentuzhigang.demo.calendar.util.DateUtil

class ScheduleActivity : AppCompatActivity() {
    private var ll_schedule // 声明一个日程表区域的线性布局对象
            : LinearLayout? = null
    private var vp_schedule // 声明一个翻页视图对象
            : ViewPager? = null
    private var mSelectedWeek // 当前选中的星期
            = 0
    private var mFestivalResid = 0 // 节日图片的资源编号
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_schedule)
        // 从布局文件中获取名叫pts_schedule的翻页标题栏
        val pts_schedule = findViewById<PagerTabStrip>(R.id.pts_schedule)
        pts_schedule.setTextSize(TypedValue.COMPLEX_UNIT_SP, 17f)
        pts_schedule.setTextColor(Color.BLACK)
        ll_schedule = findViewById(R.id.ll_schedule)
        // 从布局文件中获取名叫vp_schedule的翻页视图
        vp_schedule = findViewById(R.id.vp_schedule)
        val tv_schedule = findViewById<TextView>(R.id.tv_schedule)
        tv_schedule.setText(DateUtil.nowYearCN + " 日程安排")
        // 获取今天所处的星期在一年当中的序号
        mSelectedWeek = SpecialCalendar.todayWeek
        // 构建一个日程表的翻页适配器
        val adapter = SchedulePagerAdapter(supportFragmentManager)
        // 给vp_schedule设置日程表翻页适配器
        with(vp_schedule) {
            // 给vp_schedule设置日程表翻页适配器
            this?.setAdapter(adapter)
            // 设置vp_schedule默认显示当前周数的日程页
            this?.setCurrentItem(mSelectedWeek - 1)
            // 给vp_schedule添加页面变化监听器
            this?.addOnPageChangeListener(SheduleChangeListener())
        }
        // 延迟50毫秒再执行任务mFirst
        mHandler.postDelayed(mFirst, 50)
    }

    private val mHandler = Handler() // 声明一个处理器对象

    // 声明一个首次打开页面需要延迟执行的任务
    private val mFirst = Runnable {
        sendBroadcast(mSelectedWeek) // 发送广播,表示当前是在第几个星期
    }

    // 发送当前周数的广播
    private fun sendBroadcast(week: Int) {
        // 创建一个广播事件的意图
        val intent = Intent(ACTION_FRAGMENT_SELECTED)
        intent.putExtra(EXTRA_SELECTED_WEEK, week)
        // 通过本地的广播管理器来发送广播
        LocalBroadcastManager.getInstance(this).sendBroadcast(intent)
    }

    public override fun onStart() {
        super.onStart()
        // 创建一个节日图片的广播接收器
        festivalReceiver = FestivalControlReceiver()
        // 注册广播接收器,注册之后才能正常接收广播
        LocalBroadcastManager.getInstance(this)
            .registerReceiver(festivalReceiver!!, IntentFilter(ACTION_SHOW_FESTIVAL))
    }

    public override fun onStop() {
        super.onStop()
        // 注销广播接收器,注销之后就不再接收广播
        LocalBroadcastManager.getInstance(this).unregisterReceiver(festivalReceiver!!)
    }

    override fun onResume() {
        super.onResume()
        if (mFestivalResid != 0) { // 在横屏和竖屏之间翻转时,不会重新onCreate,只会onResume
            ll_schedule!!.setBackgroundResource(mFestivalResid)
        }
    }

    // 声明一个节日图片的广播接收器
    private var festivalReceiver: FestivalControlReceiver? = null

    // 定义一个广播接收器,用于处理节日图片事件
    private inner class FestivalControlReceiver : BroadcastReceiver() {
        // 一旦接收到节日图片的广播,马上触发接收器的onReceive方法
        override fun onReceive(context: Context, intent: Intent) {
            if (intent != null) {
                // 从广播消息中取出节日图片的资源编号
                mFestivalResid = intent.getIntExtra(EXTRA_FESTIVAL_RES, 1)
                // 把页面背景设置为广播发来的节日图片
                ll_schedule!!.setBackgroundResource(mFestivalResid)
            }
        }
    }

    // 定义一个页面变化监听器,用于处理翻页视图的翻页事件
    inner class SheduleChangeListener : OnPageChangeListener {
        // 在翻页结束后触发
        override fun onPageSelected(position: Int) {
            Log.d(TAG, "onPageSelected position=$position, mSelectedWeek=$mSelectedWeek")
            mSelectedWeek = position + 1
            sendBroadcast(mSelectedWeek)
        }

        // 在翻页过程中触发
        override fun onPageScrolled(
            position: Int,
            positionOffset: Float,
            positionOffsetPixels: Int
        ) {
        }

        // 翻页状态改变时触发
        override fun onPageScrollStateChanged(arg0: Int) {}
    }

    companion object {
        private const val TAG = "ScheduleActivity"

        // 声明一个碎片选中事件的标识串
        var ACTION_FRAGMENT_SELECTED = "io.shentuzhigang.demo.calendar.ACTION_FRAGMENT_SELECTED"

        // 声明一个选择星期参数的标识串
        var EXTRA_SELECTED_WEEK = "selected_week"

        // 声明一个显示节日事件的标识串
        var ACTION_SHOW_FESTIVAL = "io.shentuzhigang.demo.calendar.ACTION_SHOW_FESTIVAL"

        // 声明一个节日图片参数的标识串
        var EXTRA_FESTIVAL_RES = "festival_res"
    }
}

实验结果(实验最终作品截图说明)


实验心得

1、熟悉App开发常用的一些高级控件及相关工具,主要包括日期时间控件的用法、列表类视图及其适配器的用法、翻页类视图及其适配器的用法、碎片及其适配器的用法等;
2、熟悉四大组件之一广播Broadcast的基本概念与常见用法;

参考项目

参考文章

以上是关于《移动项目实践》实验报告——Android高级控件的主要内容,如果未能解决你的问题,请参考以下文章

《移动项目实践》实验报告——Android中级控件

《移动项目实践》实验报告——Android组合控件

《移动项目实践》实验报告——Android组合控件

《移动项目实践》实验报告——初级控件

《移动项目实践》实验报告——Android设备操作

《移动项目实践》实验报告——Android设备操作