Bläddra i källkod

1.卸货日期必选,时间选填。

石慧云 4 år sedan
förälder
incheckning
d642585df3
29 ändrade filer med 2743 tillägg och 330 borttagningar
  1. 2 2
      app/src/main/java/com/quansu/heifengwuliu/activity/HomeActivity.kt
  2. 17 1
      app/src/main/java/com/quansu/heifengwuliu/adapter/CarEnterAdapter.kt
  3. 1 1
      app/src/main/java/com/quansu/heifengwuliu/config/Config.kt
  4. 23 3
      app/src/main/java/com/quansu/heifengwuliu/fragment/OwnerMoreFragment.kt
  5. 38 9
      app/src/main/java/com/quansu/heifengwuliu/fragment/OwnerSingleFragment.kt
  6. 0 38
      app/src/main/java/com/quansu/heifengwuliu/fragment/TimeLeftFragment.kt
  7. 0 39
      app/src/main/java/com/quansu/heifengwuliu/fragment/TimeRightFragment.kt
  8. 96 96
      app/src/main/java/com/quansu/heifengwuliu/utils/PopuChoseTime.kt
  9. 63 0
      app/src/main/java/com/quansu/heifengwuliu/view/timeview/ItemsRange.java
  10. 10 0
      app/src/main/java/com/quansu/heifengwuliu/view/timeview/OnWheelTimeChangedListener.java
  11. 17 0
      app/src/main/java/com/quansu/heifengwuliu/view/timeview/OnWheelTimeClickedListener.java
  12. 13 0
      app/src/main/java/com/quansu/heifengwuliu/view/timeview/OnWheelTimeScrollListener.java
  13. 135 0
      app/src/main/java/com/quansu/heifengwuliu/view/timeview/WheelTimeRecycle.java
  14. 233 0
      app/src/main/java/com/quansu/heifengwuliu/view/timeview/WheelTimeScroller.java
  15. 944 0
      app/src/main/java/com/quansu/heifengwuliu/view/timeview/WheelTimeView.java
  16. 59 0
      app/src/main/java/com/quansu/heifengwuliu/view/timeview/adapter/AbstractWheelAdapter.java
  17. 254 0
      app/src/main/java/com/quansu/heifengwuliu/view/timeview/adapter/AbstractWheelTextAdapter.java
  18. 43 0
      app/src/main/java/com/quansu/heifengwuliu/view/timeview/adapter/ArrayWheelAdapter.java
  19. 121 0
      app/src/main/java/com/quansu/heifengwuliu/view/timeview/adapter/TimeNumericWheelAdapter.java
  20. 51 0
      app/src/main/java/com/quansu/heifengwuliu/view/timeview/adapter/WheelTimeViewAdapter.java
  21. 220 0
      app/src/main/java/com/quansu/heifengwuliu/widget/TimeLeftView.kt
  22. 194 0
      app/src/main/java/com/quansu/heifengwuliu/widget/TimeRightView.kt
  23. 31 0
      app/src/main/res/drawable/wheel_bg.xml
  24. 12 0
      app/src/main/res/drawable/wheel_val_time.xml
  25. 2 0
      app/src/main/res/layout/fragment_ownersingle.xml
  26. 43 57
      app/src/main/res/layout/fragment_time_left.xml
  27. 34 57
      app/src/main/res/layout/fragment_time_right.xml
  28. 84 27
      app/src/main/res/layout/item_chose_time.xml
  29. 3 0
      app/src/main/res/values/colors.xml

+ 2 - 2
app/src/main/java/com/quansu/heifengwuliu/activity/HomeActivity.kt

@@ -145,8 +145,8 @@ class HomeActivity : MBActivity<HomeVModel, ActivityHomeBinding>() {
 
         } else {
 
-           // val oneFragment = DeliverGoodsFragment()
-            val oneFragment =  OwnerSingleFragment()
+            val oneFragment = DeliverGoodsFragment()
+          //  val oneFragment =  OwnerSingleFragment()
             val twoFragment = WayBillFragment()
             val threeFragment = MineFragment()
 

+ 17 - 1
app/src/main/java/com/quansu/heifengwuliu/adapter/CarEnterAdapter.kt

@@ -6,6 +6,7 @@ import android.text.TextWatcher
 import android.view.View
 import android.view.View.OnFocusChangeListener
 import android.widget.EditText
+import androidx.fragment.app.FragmentManager
 import com.chad.library.adapter.base.viewholder.BaseDataBindingHolder
 import com.qmuiteam.qmui.widget.dialog.QMUIDialog
 import com.qmuiteam.qmui.widget.dialog.QMUIDialogAction
@@ -17,13 +18,14 @@ import com.quansu.heifengwuliu.inte.onTextChangeListener
 import com.quansu.heifengwuliu.model.SelectData
 import com.quansu.heifengwuliu.model.bean.ReceiveBean
 import com.quansu.heifengwuliu.utils.PopuBottomUtils
+import com.quansu.heifengwuliu.utils.PopuChoseTime
 import com.quansu.heifengwuliu.utils.PopupUtils
 import com.quansu.heifengwuliu.vmodel.OwnerMoreVModel
 import com.ysnows.base.base.BAdapter
 import java.text.DecimalFormat
 
 
-class CarEnterAdapter(val vm: OwnerMoreVModel) : BAdapter<ReceiveBean, BaseDataBindingHolder<ItemOutcarBinding>>(R.layout.item_outcar) {
+class CarEnterAdapter(val vm: OwnerMoreVModel,val fm:FragmentManager) : BAdapter<ReceiveBean, BaseDataBindingHolder<ItemOutcarBinding>>(R.layout.item_outcar) {
 
     var goodsTypeList = ArrayList<SelectData>()
     var numsTypeList = ArrayList<String>()
@@ -81,6 +83,20 @@ class CarEnterAdapter(val vm: OwnerMoreVModel) : BAdapter<ReceiveBean, BaseDataB
                 }
             })
 
+
+            var view=holder.dataBinding?.tvChoseTime
+            PopuChoseTime.show(context, view!!,fm,object :ChoiceData{
+                override fun onRestuse(time: String?) {
+
+                    if (time != null) {
+                        holder.dataBinding?.tvChoseTime!!.text = time
+                        item.time = time
+                    }
+                }
+            })
+
+
+
         }
 
         holder.dataBinding?.tvDelete!!.setOnClickListener {

+ 1 - 1
app/src/main/java/com/quansu/heifengwuliu/config/Config.kt

@@ -8,7 +8,7 @@ class Config : IConfig {
      // return "https://heifengwuliudev.qs110.com/"
 
       return "https://xinyunbida.qs110.com/"
-      // return "https://xinyunbidadev.qs110.com/"
+     //  return "https://xinyunbidadev.qs110.com/"
 
     }
 

+ 23 - 3
app/src/main/java/com/quansu/heifengwuliu/fragment/OwnerMoreFragment.kt

@@ -7,6 +7,7 @@ import android.text.Editable
 import android.text.TextUtils
 import android.util.Log
 import android.view.LayoutInflater
+import android.view.View
 import android.view.ViewGroup
 import androidx.lifecycle.Observer
 import com.google.gson.Gson
@@ -86,7 +87,7 @@ class OwnerMoreFragment : MBFragment<OwnerMoreVModel, FragmentOwnermoreBinding>(
         super.init(savedInstanceState)
 
         vm.initData(this)
-        adapter = CarEnterAdapter(vm)
+        adapter = CarEnterAdapter(vm,childFragmentManager)
         binding.recyclerView.adapter = adapter
         getData()
         vm.info.observe(this, Observer {
@@ -228,6 +229,11 @@ class OwnerMoreFragment : MBFragment<OwnerMoreVModel, FragmentOwnermoreBinding>(
                 toast("卸货人姓名格式不对,请检查!")
                 return
             }
+            if (TextUtils.isEmpty(item.time)) {
+                toast("请输入卸货时间")
+                return
+            }
+
             if (TextUtils.isEmpty(item.mobile)) {
                 toast("请输入卸货人电话!")
                 return
@@ -481,13 +487,27 @@ class OwnerMoreFragment : MBFragment<OwnerMoreVModel, FragmentOwnermoreBinding>(
         }
         //装货时间
         binding.viewHead.getTvChoseTime()!!.setOnClickListener {
-            PopupUtils.setChoseTime(context, binding.viewHead.getTvChoseTime(), object : ChoiceData {
+//            PopupUtils.setChoseTime(context, binding.viewHead.getTvChoseTime(), object : ChoiceData {
+//                override fun onRestuse(time: String?) {
+//                    if (time != null) {
+//                        time_out = time
+//                    }
+//                }
+//            })
+
+            var view=binding.viewHead.getTvChoseTime()
+            PopuChoseTime.show(context(), view!!,childFragmentManager,object :ChoiceData{
                 override fun onRestuse(time: String?) {
+
                     if (time != null) {
-                        time_out = time
+                        time_out = time!!
+                        binding.viewHead.getTvChoseTime()!!.text=time_out
                     }
                 }
             })
+
+
+
         }
 
     }

+ 38 - 9
app/src/main/java/com/quansu/heifengwuliu/fragment/OwnerSingleFragment.kt

@@ -91,7 +91,7 @@ class OwnerSingleFragment : MBFragment<OwnerSingleVModel, FragmentOwnersingleBin
 
     override fun init(savedInstanceState: Bundle?) {
         super.init(savedInstanceState)
-        setShow()
+       // setShow()
         getData()
 
         vm.info.observe(this, Observer {
@@ -324,10 +324,10 @@ class OwnerSingleFragment : MBFragment<OwnerSingleVModel, FragmentOwnersingleBin
             toast("请输入卸货人电话!")
             return
         }
-//        if (TextUtils.isEmpty(time_in)) {
-//            toast("请输入卸货时间")
-//            return
-//        }
+        if (TextUtils.isEmpty(time_in)) {
+            toast("请输入卸货时间")
+            return
+        }
 
         var goods_name = binding.etGoodsName.text.toString().trim()
 
@@ -560,23 +560,52 @@ class OwnerSingleFragment : MBFragment<OwnerSingleVModel, FragmentOwnersingleBin
         }
         binding.viewEnter.getTvChoseTime()!!.setOnClickListener {
             //选择时间
-            PopupUtils.setChoseTime(context, binding.viewEnter.getTvChoseTime()!!, object : ChoiceData {
+//            PopupUtils.setChoseTime(context, binding.viewEnter.getTvChoseTime()!!, object : ChoiceData {
+//                override fun onRestuse(time: String?) {
+//                    if (time != null) {
+//                        time_in = time
+//                    }
+//                }
+//            })
+
+
+            var view=binding.viewEnter.getTvChoseTime()!!
+            PopuChoseTime.show(context(), view!!,childFragmentManager,object :ChoiceData{
                 override fun onRestuse(time: String?) {
+
                     if (time != null) {
-                        time_in = time
+                        time_out = time!!
+                        binding.viewEnter.getTvChoseTime()!!.text=time_out
                     }
                 }
             })
+
+
         }
 
         binding.viewHead.getTvChoseTime()!!.setOnClickListener {
-            PopupUtils.setChoseTime(context, binding.viewHead.getTvChoseTime(), object : ChoiceData {
+//            PopupUtils.setChoseTime(context, binding.viewHead.getTvChoseTime(), object : ChoiceData {
+//                override fun onRestuse(time: String?) {
+//                    if (time != null) {
+//                        time_out = time
+//                    }
+//                }
+//            })
+
+
+
+            var view=binding.viewHead.getTvChoseTime()
+            PopuChoseTime.show(context(), view!!,childFragmentManager,object :ChoiceData{
                 override fun onRestuse(time: String?) {
+
                     if (time != null) {
-                        time_out = time
+                        time_out = time!!
+                        binding.viewHead.getTvChoseTime()!!.text=time_out
                     }
                 }
             })
+
+
         }
 
 

+ 0 - 38
app/src/main/java/com/quansu/heifengwuliu/fragment/TimeLeftFragment.kt

@@ -1,38 +0,0 @@
-package com.quansu.heifengwuliu.fragment
-
-import android.os.Bundle
-import android.text.TextUtils
-import android.util.Log
-import android.view.LayoutInflater
-import android.view.ViewGroup
-import coil.load
-import com.quansu.heifengwuliu.base.MBFragment
-import com.quansu.heifengwuliu.databinding.FragmentOwnerimgBinding
-import com.quansu.heifengwuliu.databinding.FragmentTimeLeftBinding
-import com.quansu.heifengwuliu.repository.MineRepository
-import com.quansu.heifengwuliu.vmodel.OwnerImgVModel
-import com.ysnows.base.base.BRepository
-import com.ysnows.base.base.BViewModel
-
-/**
- * 时间左边
- *Created by shihuiyun
- *on 2020/9/11
- */
-class TimeLeftFragment : MBFragment<BViewModel<MineRepository>, FragmentTimeLeftBinding>(){
-
-
-    override fun init(savedInstanceState: Bundle?) {
-        super.init(savedInstanceState)
-
-
-    }
-
-    override fun binding(inflater: LayoutInflater, container: ViewGroup?): FragmentTimeLeftBinding {
-       return  FragmentTimeLeftBinding.inflate(layoutInflater)
-    }
-
-    override fun title(): String? {
-        return null
-    }
-}

+ 0 - 39
app/src/main/java/com/quansu/heifengwuliu/fragment/TimeRightFragment.kt

@@ -1,39 +0,0 @@
-package com.quansu.heifengwuliu.fragment
-
-import android.os.Bundle
-import android.text.TextUtils
-import android.util.Log
-import android.view.LayoutInflater
-import android.view.ViewGroup
-import coil.load
-import com.quansu.heifengwuliu.base.MBFragment
-import com.quansu.heifengwuliu.databinding.FragmentOwnerimgBinding
-import com.quansu.heifengwuliu.databinding.FragmentTimeLeftBinding
-import com.quansu.heifengwuliu.databinding.FragmentTimeRightBinding
-import com.quansu.heifengwuliu.repository.MineRepository
-import com.quansu.heifengwuliu.vmodel.OwnerImgVModel
-import com.ysnows.base.base.BRepository
-import com.ysnows.base.base.BViewModel
-
-/**
- * 时间右边
- *Created by shihuiyun
- *on 2020/9/11
- */
-class TimeRightFragment : MBFragment<BViewModel<MineRepository>, FragmentTimeRightBinding>(){
-
-
-    override fun init(savedInstanceState: Bundle?) {
-        super.init(savedInstanceState)
-
-
-    }
-
-    override fun binding(inflater: LayoutInflater, container: ViewGroup?): FragmentTimeRightBinding {
-       return  FragmentTimeRightBinding.inflate(layoutInflater)
-    }
-
-    override fun title(): String? {
-        return null
-    }
-}

+ 96 - 96
app/src/main/java/com/quansu/heifengwuliu/utils/PopuChoseTime.kt

@@ -1,31 +1,28 @@
 package com.quansu.heifengwuliu.utils
 
 import android.content.Context
-import android.graphics.Color
+import android.text.TextUtils
+import android.util.Log
 import android.view.LayoutInflater
 import android.view.View
 import android.widget.FrameLayout
+import android.widget.LinearLayout
 import android.widget.TextView
-import androidx.fragment.app.Fragment
+import android.widget.Toast
 import androidx.fragment.app.FragmentManager
-import com.hwangjr.rxbus.RxBus
 import com.qmuiteam.qmui.kotlin.onClick
 import com.qmuiteam.qmui.layout.QMUIFrameLayout
 import com.qmuiteam.qmui.skin.QMUISkinValueBuilder
 import com.qmuiteam.qmui.util.QMUIDisplayHelper
-import com.qmuiteam.qmui.widget.QMUIViewPager
 import com.qmuiteam.qmui.widget.popup.QMUIPopup
 import com.qmuiteam.qmui.widget.popup.QMUIPopups
-import com.qmuiteam.qmui.widget.tab.QMUITab
-import com.qmuiteam.qmui.widget.tab.QMUITabIndicator
-import com.qmuiteam.qmui.widget.tab.QMUITabSegment
 import com.quansu.heifengwuliu.R
-import com.quansu.heifengwuliu.adapter.BaseFragmentPagerAdapter
-import com.quansu.heifengwuliu.config.ConfigRx
-import com.quansu.heifengwuliu.fragment.OwnerImgFragment
-import com.quansu.heifengwuliu.fragment.TimeLeftFragment
-import com.quansu.heifengwuliu.fragment.TimeRightFragment
 import com.quansu.heifengwuliu.inte.ChoiceData
+import com.quansu.heifengwuliu.inte.ChoiceListData
+import com.quansu.heifengwuliu.widget.TimeLeftView
+import com.quansu.heifengwuliu.widget.TimeRightView
+import java.text.SimpleDateFormat
+import java.util.*
 
 /**
  * 选择时间
@@ -34,8 +31,11 @@ import com.quansu.heifengwuliu.inte.ChoiceData
  */
 object PopuChoseTime {
 
+    var time1 = ""
+    var time2 = ""
 
-    fun show(context: Context, text: String, view: View, fm: FragmentManager, choiceData: ChoiceData) {
+
+    fun show(context: Context, view: View, fm: FragmentManager, choiceCallData: ChoiceData) {
 
         var mNormalPopup = QMUIPopups.fullScreenPopup(context)
         val builder: QMUISkinValueBuilder = QMUISkinValueBuilder.acquire()
@@ -43,110 +43,109 @@ object PopuChoseTime {
         //自定义布局
         val layoutInflater = context?.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
         var layout = layoutInflater.inflate(R.layout.item_chose_time, null)
+        val  ll:LinearLayout = layout.findViewById(R.id.ll)
 
-        val tvTitle: TextView = layout.findViewById(R.id.tv_title)
+        val llData: LinearLayout = layout.findViewById(R.id.ll_data)
+        val tvData: TextView = layout.findViewById(R.id.tv_data)
+        val lineData: View = layout.findViewById(R.id.line_data)
+        val llTime: LinearLayout = layout.findViewById(R.id.ll_time)
         val tvTime: TextView = layout.findViewById(R.id.tv_time)
-        val tabs: QMUITabSegment = layout.findViewById(R.id.tabs)
+        val lineTime: View = layout.findViewById(R.id.line_time)
         val tvSure: TextView = layout.findViewById(R.id.tv_sure)
-        val qmViewPager: QMUIViewPager = layout.findViewById(R.id.qm_view_pager)
-        //设置viewpager
-        val fragments = ArrayList<Fragment>()
-
-        var oneTimeLeft = TimeLeftFragment()
-        var oneTimeRight = TimeRightFragment()
-        fragments.add(oneTimeLeft)
-        fragments.add(oneTimeRight)
-
-        val adapter = BaseFragmentPagerAdapter(fm, fragments)//childFragmentManager
-        qmViewPager.adapter = adapter
-        //设置tab
-        tabs.setIndicator(QMUITabIndicator(QMUIDisplayHelper.dp2px(context, 2), false, true))
-        val space: Int = QMUIDisplayHelper.dp2px(context, 20)
-        tabs.setItemSpaceInScrollMode(space)
-        tabs.setPadding(space, 0, space, 0)
-        tabs.mode = QMUITabSegment.MODE_SCROLLABLE
-        tabs.right = space
-
-        val sizeTabs: Int = QMUIDisplayHelper.dp2px(context, 14)
-
-        val builder1 = tabs.tabBuilder()
-        builder1
-                .skinChangeWithTintColor(false)
-                .setSelectColor(Color.parseColor("#FFBC00"))
-                .setNormalColor(Color.parseColor("#5E5F60"))
-                // .setTypeface(Typeface.DEFAULT_BOLD, Typeface.DEFAULT)
-                .setTextSize(sizeTabs, sizeTabs)
-                .setDynamicChangeIconColor(false)
-
-        val tabList = ArrayList<QMUITab>()
-
-        val item1 = builder1
-                .setText("年月日")
-                .build(context)
-        tabList.add(item1)
-
-        val item2 = builder1
-                .setText("时分秒")
-                .build(context)
-        tabList.add(item2)
-
-        tabList.forEach {
-            tabs.addTab(it)
-        }
-        tabs.setupWithViewPager(qmViewPager, false)
-        tabs.addOnTabSelectedListener(object : QMUITabSegment.OnTabSelectedListener {
-            //mTabSegment选项被选中的监听
-            /**
-             * 当某个 Tab 被选中时会触发
-             *
-             * @param index 被选中的 Tab 下标
-             */
-            override fun onTabSelected(index: Int) {
+
+        val timeLeft: TimeLeftView = layout.findViewById(R.id.time_left)
+        val timeRight: TimeRightView = layout.findViewById(R.id.time_right)
 
 
-            }
 
-            /**
-             * 当某个 Tab 被取消选中时会触发
-             *
-             * @param index 被取消选中的 Tab 下标
-             */
-            override fun onTabUnselected(index: Int) {}
+        timeLeft.setCallBack(object : ChoiceListData {
+            override fun onRestuse(code: String?, name: String?) {
 
-            /**
-             * 当某个 Tab 处于被选中状态下再次被点击时会触发
-             *
-             * @param index 被再次点击的 Tab 下标
-             */
-            override fun onTabReselected(index: Int) {
+                time1 = name!!
+                tvData.text = time1
 
 
             }
+        })
+        timeRight.setCallBack(object : ChoiceListData {
+            override fun onRestuse(code: String?, name: String?) {
+
+                time2 = name!!
+                tvTime.text = time2
+
 
-            /**
-             * 当某个 Tab 被双击时会触发
-             *
-             * @param index 被双击的 Tab 下标
-             */
-            override fun onDoubleTap(index: Int) {}
+            }
         })
 
+        tvSure.onClick {
+
+            if(TextUtils.isEmpty(time1)){
+                Toast.makeText(context, "请选择年月日", Toast.LENGTH_SHORT).show()
+                return@onClick
+            }
+            var time=""
+            time = if (!TextUtils.isEmpty(time2)) {
+                "$time1 $time2"
+            } else {
+                time1
+            }
+
+            //可根据需要自行截取数据显示
+            //24小时制 日期格式必须一致才可
+            var df = if (!TextUtils.isEmpty(time2)) {
+                SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
+            }else{
+                SimpleDateFormat("yyyy-MM-dd")
+            }
 
-//        tvSure.onClick {
-//
-//            choiceData?.onRestuse("")
-//
-//            mNormalPopup.dismiss()
-//        }
+            val calendar: Calendar = Calendar.getInstance()
+            val endTime: String = df.format(calendar.time)
 
+            val i: Int = time.compareTo(endTime)
+            if(i<0){
+                Toast.makeText(context, "选择的时间不能小于当前时间!", Toast.LENGTH_SHORT).show()
+                return@onClick
+
+            }
+            Log.e("-shy-", "time= $time")
+            if(null!=choiceCallData){
+                Log.e("-shy-", "1111 ")
+                choiceCallData!!.onRestuse(time)
+            }
+            mNormalPopup?.dismiss()
+        }
+
+
+        llData.onClick {
+            lineData.visibility = View.VISIBLE
+            lineTime.visibility = View.INVISIBLE
+            timeLeft.visibility = View.VISIBLE
+            timeRight.visibility = View.GONE
+        }
+        llTime.onClick {
+            lineTime.visibility = View.VISIBLE
+            lineData.visibility = View.INVISIBLE
+            timeRight.visibility = View.VISIBLE
+            timeLeft.visibility = View.GONE
+
+            if(TextUtils.isEmpty(time2)){
+                time2 = timeRight.getTime()
+                tvTime.text = time2
+            }
+        }
+
+        ll.onClick {
+            mNormalPopup?.dismiss()
+        }
 
         builder.release();
 
         val size = QMUIDisplayHelper.getScreenWidth(context)
+        val height = QMUIDisplayHelper.getScreenHeight(context)
 
 
         val lp: FrameLayout.LayoutParams = FrameLayout.LayoutParams(size,
-                FrameLayout.LayoutParams.WRAP_CONTENT)
+                height)
         frameLayout.addView(layout, lp)
 
         mNormalPopup.addView(frameLayout)
@@ -154,10 +153,11 @@ object PopuChoseTime {
         }
 
         mNormalPopup.dismissIfOutsideTouch(false)
-        mNormalPopup.animStyle(QMUIPopup.ANIM_GROW_FROM_CENTER)
+        mNormalPopup.animStyle(QMUIPopup.ANIM_AUTO)
         mNormalPopup.show(view)
 
 
     }
 
+
 }

+ 63 - 0
app/src/main/java/com/quansu/heifengwuliu/view/timeview/ItemsRange.java

@@ -0,0 +1,63 @@
+
+package com.quansu.heifengwuliu.view.timeview;
+
+/**
+ * Range for visible items.
+ */
+public class ItemsRange {
+	// First item number
+	private int first;
+	
+	// Items count
+	private int count;
+
+	/**
+	 * Default constructor. Creates an empty range
+	 */
+    public ItemsRange() {
+        this(0, 0);
+    }
+    
+	/**
+	 * Constructor
+	 * @param first the number of first item
+	 * @param count the count of items
+	 */
+	public ItemsRange(int first, int count) {
+		this.first = first;
+		this.count = count;
+	}
+	
+	/**
+	 * Gets number of  first item
+	 * @return the number of the first item
+	 */
+	public int getFirst() {
+		return first;
+	}
+	
+	/**
+	 * Gets number of last item
+	 * @return the number of last item
+	 */
+	public int getLast() {
+		return getFirst() + getCount() - 1;
+	}
+	
+	/**
+	 * Get items count
+	 * @return the count of items
+	 */
+	public int getCount() {
+		return count;
+	}
+	
+	/**
+	 * Tests whether item is contained by range
+	 * @param index the item number
+	 * @return true if item is contained
+	 */
+	public boolean contains(int index) {
+		return index >= getFirst() && index <= getLast();
+	}
+}

+ 10 - 0
app/src/main/java/com/quansu/heifengwuliu/view/timeview/OnWheelTimeChangedListener.java

@@ -0,0 +1,10 @@
+package com.quansu.heifengwuliu.view.timeview;
+
+/**
+ * Created by shihuiyun
+ * on 2020/11/23
+ */
+public interface OnWheelTimeChangedListener {
+    void onChanged(WheelTimeView wheel, int oldValue, int newValue);
+
+}

+ 17 - 0
app/src/main/java/com/quansu/heifengwuliu/view/timeview/OnWheelTimeClickedListener.java

@@ -0,0 +1,17 @@
+
+package com.quansu.heifengwuliu.view.timeview;
+
+/**
+ * Wheel clicked listener interface.
+ * <p>The onItemClicked() method is called whenever a wheel item is clicked
+ * <li> New Wheel position is set
+ * <li> Wheel view is scrolled
+ */
+public interface OnWheelTimeClickedListener {
+    /**
+     * Callback method to be invoked when current item clicked
+     * @param wheel the wheel view
+     * @param itemIndex the index of clicked item
+     */
+    void onItemClicked(WheelTimeView wheel, int itemIndex);
+}

+ 13 - 0
app/src/main/java/com/quansu/heifengwuliu/view/timeview/OnWheelTimeScrollListener.java

@@ -0,0 +1,13 @@
+package com.quansu.heifengwuliu.view.timeview;
+
+/**
+ * Created by shihuiyun
+ * on 2020/11/23
+ */
+public interface OnWheelTimeScrollListener {
+
+    void onScrollingStarted(WheelTimeView wheel);
+
+    void onScrollingFinished(WheelTimeView wheel);
+
+}

+ 135 - 0
app/src/main/java/com/quansu/heifengwuliu/view/timeview/WheelTimeRecycle.java

@@ -0,0 +1,135 @@
+
+package com.quansu.heifengwuliu.view.timeview;
+
+import android.view.View;
+import android.widget.LinearLayout;
+
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Recycle stores wheel items to reuse. 
+ */
+public class WheelTimeRecycle {
+	// Cached items
+	private List<View> items;
+	
+	// Cached empty items
+	private List<View> emptyItems;
+	
+	// Wheel view
+	private WheelTimeView wheel;
+	
+	/**
+	 * Constructor
+	 * @param wheel the wheel view
+	 */
+	public WheelTimeRecycle(WheelTimeView wheel) {
+		this.wheel = wheel;
+	}
+
+	/**
+	 * Recycles items from specified layout.
+	 * There are saved only items not included to specified range.
+	 * All the cached items are removed from original layout.
+	 * 
+	 * @param layout the layout containing items to be cached
+	 * @param firstItem the number of first item in layout
+	 * @param range the range of current wheel items 
+	 * @return the new value of first item number
+	 */
+	public int recycleItems(LinearLayout layout, int firstItem, ItemsRange range) {
+		int index = firstItem;
+		for (int i = 0; i < layout.getChildCount();) {
+			if (!range.contains(index)) {
+				recycleView(layout.getChildAt(i), index);
+				layout.removeViewAt(i);
+				if (i == 0) { // first item
+					firstItem++;
+				}
+			} else {
+				i++; // go to next item
+			}
+			index++;
+		}
+		return firstItem;
+	}
+	
+	/**
+	 * Gets item view
+	 * @return the cached view
+	 */
+	public View getItem() {
+		return getCachedView(items);
+	}
+
+	/**
+	 * Gets empty item view
+	 * @return the cached empty view
+	 */
+	public View getEmptyItem() {
+		return getCachedView(emptyItems);
+	}
+	
+	/**
+	 * Clears all views 
+	 */
+	public void clearAll() {
+		if (items != null) {
+			items.clear();
+		}
+		if (emptyItems != null) {
+			emptyItems.clear();
+		}
+	}
+
+	/**
+	 * Adds view to specified cache. Creates a cache list if it is null.
+	 * @param view the view to be cached
+	 * @param cache the cache list
+	 * @return the cache list
+	 */
+	private List<View> addView(View view, List<View> cache) {
+		if (cache == null) {
+			cache = new LinkedList<View>();
+		}
+		
+		cache.add(view);
+		return cache;
+	}
+
+	/**
+	 * Adds view to cache. Determines view type (item view or empty one) by index.
+	 * @param view the view to be cached
+	 * @param index the index of view
+	 */
+	private void recycleView(View view, int index) {
+		int count = wheel.getViewAdapter().getItemsCount();
+
+		if ((index < 0 || index >= count) && !wheel.isCyclic()) {
+			// empty view
+			emptyItems = addView(view, emptyItems);
+		} else {
+			while (index < 0) {
+				index = count + index;
+			}
+			index %= count;
+			items = addView(view, items);
+		}
+	}
+	
+	/**
+	 * Gets view from specified cache.
+	 * @param cache the cache
+	 * @return the first view from cache.
+	 */
+	private View getCachedView(List<View> cache) {
+		if (cache != null && cache.size() > 0) {
+			View view = cache.get(0);
+			cache.remove(0);
+			return view;
+		}
+		return null;
+	}
+
+}

+ 233 - 0
app/src/main/java/com/quansu/heifengwuliu/view/timeview/WheelTimeScroller.java

@@ -0,0 +1,233 @@
+package com.quansu.heifengwuliu.view.timeview;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.Message;
+import android.view.GestureDetector;
+import android.view.GestureDetector.SimpleOnGestureListener;
+import android.view.MotionEvent;
+import android.view.animation.Interpolator;
+import android.widget.Scroller;
+
+/**
+ * Scroller class handles scrolling events and updates the 
+ */
+public class WheelTimeScroller {
+    /**
+     * Scrolling listener interface
+     */
+    public interface ScrollingListener {
+        /**
+         * Scrolling callback called when scrolling is performed.
+         * @param distance the distance to scroll
+         */
+        void onScroll(int distance);
+
+        /**
+         * Starting callback called when scrolling is started
+         */
+        void onStarted();
+        
+        /**
+         * Finishing callback called after justifying
+         */
+        void onFinished();
+        
+        /**
+         * Justifying callback called to justify a view when scrolling is ended
+         */
+        void onJustify();
+    }
+    
+    /** Scrolling duration */
+    private static final int SCROLLING_DURATION = 400;
+
+    /** Minimum delta for scrolling */
+    public static final int MIN_DELTA_FOR_SCROLLING = 1;
+
+    // Listener
+    private ScrollingListener listener;
+    
+    // Context
+    private Context context;
+    
+    // Scrolling
+    private GestureDetector gestureDetector;
+    private Scroller scroller;
+    private int lastScrollY;
+    private float lastTouchedY;
+    private boolean isScrollingPerformed;
+
+    /**
+     * Constructor
+     * @param context the current context
+     * @param listener the scrolling listener
+     */
+    public WheelTimeScroller(Context context, ScrollingListener listener) {
+        gestureDetector = new GestureDetector(context, gestureListener);
+        gestureDetector.setIsLongpressEnabled(false);
+        
+        scroller = new Scroller(context);
+
+        this.listener = listener;
+        this.context = context;
+    }
+    
+    /**
+     * Set the the specified scrolling interpolator
+     * @param interpolator the interpolator
+     */
+    public void setInterpolator(Interpolator interpolator) {
+        scroller.forceFinished(true);
+        scroller = new Scroller(context, interpolator);
+    }
+    
+    /**
+     * Scroll the wheel
+     * @param distance the scrolling distance
+     * @param time the scrolling duration
+     */
+    public void scroll(int distance, int time) {
+        scroller.forceFinished(true);
+
+        lastScrollY = 0;
+        
+        scroller.startScroll(0, 0, 0, distance, time != 0 ? time : SCROLLING_DURATION);
+        setNextMessage(MESSAGE_SCROLL);
+        
+        startScrolling();
+    }
+   
+    /**
+     * Stops scrolling
+     */
+    public void stopScrolling() {
+        scroller.forceFinished(true);
+    }
+    
+    /**
+     * Handles Touch event 
+     * @param event the motion event
+     * @return
+     */
+    public boolean onTouchEvent(MotionEvent event) {
+        switch (event.getAction()) {
+            case MotionEvent.ACTION_DOWN:
+                lastTouchedY = event.getY();
+                scroller.forceFinished(true);
+                clearMessages();
+                break;
+    
+            case MotionEvent.ACTION_MOVE:
+                // perform scrolling
+                int distanceY = (int)(event.getY() - lastTouchedY);
+                if (distanceY != 0) {
+                    startScrolling();
+                    listener.onScroll(distanceY);
+                    lastTouchedY = event.getY();
+                }
+                break;
+        }
+        
+        if (!gestureDetector.onTouchEvent(event) && event.getAction() == MotionEvent.ACTION_UP) {
+            justify();
+        }
+
+        return true;
+    }
+    
+    // gesture listener
+    private SimpleOnGestureListener gestureListener = new SimpleOnGestureListener() {
+        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
+            // Do scrolling in onTouchEvent() since onScroll() are not call immediately
+            //  when user touch and move the wheel
+            return true;
+        }
+        
+        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
+            lastScrollY = 0;
+            final int maxY = 0x7FFFFFFF;
+            final int minY = -maxY;
+            scroller.fling(0, lastScrollY, 0, (int) -velocityY, 0, 0, minY, maxY);
+            setNextMessage(MESSAGE_SCROLL);
+            return true;
+        }
+    };
+
+    // Messages
+    private final int MESSAGE_SCROLL = 0;
+    private final int MESSAGE_JUSTIFY = 1;
+    
+    /**
+     * Set next message to queue. Clears queue before.
+     * 
+     * @param message the message to set
+     */
+    private void setNextMessage(int message) {
+        clearMessages();
+        animationHandler.sendEmptyMessage(message);
+    }
+
+    /**
+     * Clears messages from queue
+     */
+    private void clearMessages() {
+        animationHandler.removeMessages(MESSAGE_SCROLL);
+        animationHandler.removeMessages(MESSAGE_JUSTIFY);
+    }
+    
+    // animation handler
+    private Handler animationHandler = new Handler() {
+        public void handleMessage(Message msg) {
+            scroller.computeScrollOffset();
+            int currY = scroller.getCurrY();
+            int delta = lastScrollY - currY;
+            lastScrollY = currY;
+            if (delta != 0) {
+                listener.onScroll(delta);
+            }
+            
+            // scrolling is not finished when it comes to final Y
+            // so, finish it manually 
+            if (Math.abs(currY - scroller.getFinalY()) < MIN_DELTA_FOR_SCROLLING) {
+                currY = scroller.getFinalY();
+                scroller.forceFinished(true);
+            }
+            if (!scroller.isFinished()) {
+                animationHandler.sendEmptyMessage(msg.what);
+            } else if (msg.what == MESSAGE_SCROLL) {
+                justify();
+            } else {
+                finishScrolling();
+            }
+        }
+    };
+    
+    /**
+     * Justifies wheel
+     */
+    private void justify() {
+        listener.onJustify();
+        setNextMessage(MESSAGE_JUSTIFY);
+    }
+
+    /**
+     * Starts scrolling
+     */
+    private void startScrolling() {
+        if (!isScrollingPerformed) {
+            isScrollingPerformed = true;
+            listener.onStarted();
+        }
+    }
+
+    /**
+     * Finishes scrolling
+     */
+    void finishScrolling() {
+        if (isScrollingPerformed) {
+            listener.onFinished();
+            isScrollingPerformed = false;
+        }
+    }
+}

+ 944 - 0
app/src/main/java/com/quansu/heifengwuliu/view/timeview/WheelTimeView.java

@@ -0,0 +1,944 @@
+
+package com.quansu.heifengwuliu.view.timeview;
+
+import android.content.Context;
+import android.database.DataSetObserver;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.GradientDrawable;
+import android.graphics.drawable.GradientDrawable.Orientation;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup.LayoutParams;
+import android.view.animation.Interpolator;
+import android.widget.LinearLayout;
+
+import com.quansu.heifengwuliu.R;
+import com.quansu.heifengwuliu.view.timeview.adapter.WheelTimeViewAdapter;
+
+import java.util.LinkedList;
+import java.util.List;
+
+
+/**
+ * Numeric wheel view.
+ * 
+ * @author Yuri Kanivets
+ */
+public class WheelTimeView extends View {
+
+	/**
+	 *  Top and bottom shadows colors
+	 *
+	 *  */
+	// TODO 设置透明度
+	private int[] SHADOWS_COLORS = new int[] { 0xefffffff,
+			0xcfffffff, 0x3fffffff };
+
+	/** Top and bottom items offset (to hide that) */
+	private static final int ITEM_OFFSET_PERCENT = 0;
+
+	/** Left and right padding value */
+	private static final int PADDING = 10;
+
+	/** Default count of visible items */
+	// TODO 默认显示几行数据
+	private static final int DEF_VISIBLE_ITEMS = 5;
+
+	// Wheel Values
+	private int currentItem = 0;
+
+	// Count of visible items
+	private int visibleItems = DEF_VISIBLE_ITEMS;
+
+	// Item height
+	private int itemHeight = 0;
+
+	// Center Line
+	private Drawable centerDrawable;
+
+	// Wheel drawables
+	//private int wheelBackground = R.drawable.wheel_bg;
+	private int wheelForeground = R.drawable.wheel_val_time;
+
+	// Shadows drawables
+	private GradientDrawable topShadow;
+	private GradientDrawable bottomShadow;
+
+	// Draw Shadows
+	private boolean drawShadows = true;
+
+	// Scrolling
+	private WheelTimeScroller scroller;
+	private boolean isScrollingPerformed;
+	private int scrollingOffset;
+
+	// Cyclic
+	boolean isCyclic = false;
+
+	// Items layout
+	private LinearLayout itemsLayout;
+
+	// The number of first item in layout
+	private int firstItem;
+
+	// View adapter
+	private WheelTimeViewAdapter viewAdapter;
+
+	// Recycle
+	private WheelTimeRecycle recycle = new WheelTimeRecycle(this);
+
+	// Listeners
+	private List<OnWheelTimeChangedListener> changingListeners = new LinkedList<OnWheelTimeChangedListener>();
+	private List<OnWheelTimeScrollListener> scrollingListeners = new LinkedList<OnWheelTimeScrollListener>();
+	private List<OnWheelTimeClickedListener> clickingListeners = new LinkedList<OnWheelTimeClickedListener>();
+	
+	String label="";
+
+	/**
+	 * Constructor
+	 */
+	public WheelTimeView(Context context, AttributeSet attrs, int defStyle) {
+		super(context, attrs, defStyle);
+		initData(context);
+	}
+
+	/**
+	 * Constructor
+	 */
+	public WheelTimeView(Context context, AttributeSet attrs) {
+		super(context, attrs);
+		initData(context);
+	}
+
+	/**
+	 * Constructor
+	 */
+	public WheelTimeView(Context context) {
+		super(context);
+		initData(context);
+	}
+
+	/**
+	 * Initializes class data
+	 * @param context the context
+	 */
+	private void initData(Context context) {
+		scroller = new WheelTimeScroller(getContext(), scrollingListener);
+	}
+
+	// Scrolling listener
+	WheelTimeScroller.ScrollingListener scrollingListener = new WheelTimeScroller.ScrollingListener() {
+		@Override
+		public void onStarted() {
+			isScrollingPerformed = true;
+			notifyScrollingListenersAboutStart();
+		}
+
+		@Override
+		public void onScroll(int distance) {
+			doScroll(distance);
+
+			int height = getHeight();
+			if (scrollingOffset > height) {
+				scrollingOffset = height;
+				scroller.stopScrolling();
+			} else if (scrollingOffset < -height) {
+				scrollingOffset = -height;
+				scroller.stopScrolling();
+			}
+		}
+
+		@Override
+		public void onFinished() {
+			if (isScrollingPerformed) {
+				notifyScrollingListenersAboutEnd();
+				isScrollingPerformed = false;
+			}
+
+			scrollingOffset = 0;
+			invalidate();
+		}
+
+		@Override
+		public void onJustify() {
+			if (Math.abs(scrollingOffset) > WheelTimeScroller.MIN_DELTA_FOR_SCROLLING) {
+				scroller.scroll(scrollingOffset, 0);
+			}
+		}
+	};
+
+	/**
+	 * Set the the specified scrolling interpolator
+	 * @param interpolator the interpolator
+	 */
+	public void setInterpolator(Interpolator interpolator) {
+		scroller.setInterpolator(interpolator);
+	}
+
+	/**
+	 * Gets count of visible items
+	 * 
+	 * @return the count of visible items
+	 */
+	public int getVisibleItems() {
+		return visibleItems;
+	}
+
+	/**
+	 * Sets the desired count of visible items.
+	 * Actual amount of visible items depends on wheel layout parameters.
+	 * To apply changes and rebuild view call measure().
+	 * 
+	 * @param count the desired count for visible items
+	 */
+	public void setVisibleItems(int count) {
+		visibleItems = count;
+	}
+
+	/**
+	 * Gets view adapter
+	 * @return the view adapter
+	 */
+	public WheelTimeViewAdapter getViewAdapter() {
+		return viewAdapter;
+	}
+
+	// Adapter listener
+	private DataSetObserver dataObserver = new DataSetObserver() {
+		@Override
+		public void onChanged() {
+			invalidateWheel(false);
+		}
+
+		@Override
+		public void onInvalidated() {
+			invalidateWheel(true);
+		}
+	};
+
+	/**
+	 * Sets view adapter. Usually new adapters contain different views, so
+	 * it needs to rebuild view by calling measure().
+	 * 
+	 * @param viewAdapter the view adapter
+	 */
+	public void setViewAdapter(WheelTimeViewAdapter viewAdapter) {
+		if (this.viewAdapter != null) {
+			this.viewAdapter.unregisterDataSetObserver(dataObserver);
+		}
+		this.viewAdapter = viewAdapter;
+		if (this.viewAdapter != null) {
+			this.viewAdapter.registerDataSetObserver(dataObserver);
+		}
+
+		invalidateWheel(true);
+	}
+
+	/**
+	 * Adds wheel changing listener
+	 * @param listener the listener
+	 */
+	public void addChangingListener(OnWheelTimeChangedListener listener) {
+		changingListeners.add(listener);
+	}
+
+	/**
+	 * Removes wheel changing listener
+	 * @param listener the listener
+	 */
+	public void removeChangingListener(OnWheelTimeChangedListener listener) {
+		changingListeners.remove(listener);
+	}
+
+	/**
+	 * Notifies changing listeners
+	 * @param oldValue the old wheel value
+	 * @param newValue the new wheel value
+	 */
+	protected void notifyChangingListeners(int oldValue, int newValue) {
+		for (OnWheelTimeChangedListener listener : changingListeners) {
+			listener.onChanged(this, oldValue, newValue);
+		}
+	}
+
+	/**
+	 * Adds wheel scrolling listener
+	 * @param listener the listener
+	 */
+	public void addScrollingListener(OnWheelTimeScrollListener listener) {
+		scrollingListeners.add(listener);
+	}
+
+	/**
+	 * Removes wheel scrolling listener
+	 * @param listener the listener
+	 */
+	public void removeScrollingListener(OnWheelTimeScrollListener listener) {
+		scrollingListeners.remove(listener);
+	}
+
+	/**
+	 * Notifies listeners about starting scrolling
+	 */
+	protected void notifyScrollingListenersAboutStart() {
+		for (OnWheelTimeScrollListener listener : scrollingListeners) {
+			listener.onScrollingStarted(this);
+		}
+	}
+
+	/**
+	 * Notifies listeners about ending scrolling
+	 */
+	protected void notifyScrollingListenersAboutEnd() {
+		for (OnWheelTimeScrollListener listener : scrollingListeners) {
+			listener.onScrollingFinished(this);
+		}
+	}
+
+	/**
+	 * Adds wheel clicking listener
+	 * @param listener the listener
+	 */
+	public void addClickingListener(OnWheelTimeClickedListener listener) {
+		clickingListeners.add(listener);
+	}
+
+	/**
+	 * Removes wheel clicking listener
+	 * @param listener the listener
+	 */
+	public void removeClickingListener(OnWheelTimeClickedListener listener) {
+		clickingListeners.remove(listener);
+	}
+
+	/**
+	 * Notifies listeners about clicking
+	 */
+	protected void notifyClickListenersAboutClick(int item) {
+		for (OnWheelTimeClickedListener listener : clickingListeners) {
+			listener.onItemClicked(this, item);
+		}
+	}
+
+	/**
+	 * Gets current value
+	 * 
+	 * @return the current value
+	 */
+	public int getCurrentItem() {
+		return currentItem;
+	}
+
+	/**
+	 * Sets the current item. Does nothing when index is wrong.
+	 * 
+	 * @param index the item index
+	 * @param animated the animation flag
+	 */
+	public void setCurrentItem(int index, boolean animated) {
+		if (viewAdapter == null || viewAdapter.getItemsCount() == 0) {
+			return; // throw?
+		}
+
+		int itemCount = viewAdapter.getItemsCount();
+		if (index < 0 || index >= itemCount) {
+			if (isCyclic) {
+				while (index < 0) {
+					index += itemCount;
+				}
+				index %= itemCount;
+			} else{
+				return; // throw?
+			}
+		}
+		if (index != currentItem) {
+			if (animated) {
+				int itemsToScroll = index - currentItem;
+				if (isCyclic) {
+					int scroll = itemCount + Math.min(index, currentItem) - Math.max(index, currentItem);
+					if (scroll < Math.abs(itemsToScroll)) {
+						itemsToScroll = itemsToScroll < 0 ? scroll : -scroll;
+					}
+				}
+				scroll(itemsToScroll, 0);
+			} else {
+				scrollingOffset = 0;
+
+				int old = currentItem;
+				currentItem = index;
+
+				notifyChangingListeners(old, currentItem);
+
+				invalidate();
+			}
+		}
+	}
+
+	/**
+	 * Sets the current item w/o animation. Does nothing when index is wrong.
+	 * 
+	 * @param index the item index
+	 */
+	public void setCurrentItem(int index) {
+		setCurrentItem(index, false);
+	}
+
+	/**
+	 * Tests if wheel is cyclic. That means before the 1st item there is shown the last one
+	 * @return true if wheel is cyclic
+	 */
+	public boolean isCyclic() {
+		return isCyclic;
+	}
+
+	/**
+	 * Set wheel cyclic flag
+	 * @param isCyclic the flag to set
+	 */
+	public void setCyclic(boolean isCyclic) {
+		this.isCyclic = isCyclic;
+		invalidateWheel(false);
+	}
+
+	/**
+	 * Determine whether shadows are drawn
+	 * @return true is shadows are drawn
+	 */
+	public boolean drawShadows() {
+		return drawShadows;
+	}
+
+	/**
+	 * Set whether shadows should be drawn
+	 * @param drawShadows flag as true or false
+	 */
+	public void setDrawShadows(boolean drawShadows) {
+		this.drawShadows = drawShadows;
+	}
+
+	/**
+	 * Set the shadow gradient color
+	 * @param start
+	 * @param middle
+	 * @param end
+	 */
+	public void setShadowColor(int start, int middle, int end) {
+		SHADOWS_COLORS = new int[] {start, middle, end};
+	}
+
+	/**
+	 * Sets the drawable for the wheel background
+	 * @param resource
+	 */
+//	public void setWheelBackground(int resource) {
+//		wheelBackground = resource;
+//		setBackgroundResource(wheelBackground);
+//	}
+
+	/**
+	 * Sets the drawable for the wheel foreground
+	 * @param resource
+	 */
+	public void setWheelForeground(int resource) {
+		wheelForeground = resource;
+		centerDrawable = getContext().getResources().getDrawable(wheelForeground);
+	}
+
+	/**
+	 * Invalidates wheel
+	 * @param clearCaches if true then cached views will be clear
+	 */
+	public void invalidateWheel(boolean clearCaches) {
+		if (clearCaches) {
+			recycle.clearAll();
+			if (itemsLayout != null) {
+				itemsLayout.removeAllViews();
+			}
+			scrollingOffset = 0;
+		} else if (itemsLayout != null) {
+			// cache all items
+			recycle.recycleItems(itemsLayout, firstItem, new ItemsRange());
+		}
+
+		invalidate();
+	}
+
+	/**
+	 * Initializes resources
+	 */
+	private void initResourcesIfNecessary() {
+		if (centerDrawable == null) {
+			centerDrawable = getContext().getResources().getDrawable(wheelForeground);
+		}
+
+		if (topShadow == null) {
+			topShadow = new GradientDrawable(Orientation.TOP_BOTTOM, SHADOWS_COLORS);
+		}
+
+		if (bottomShadow == null) {
+			bottomShadow = new GradientDrawable(Orientation.BOTTOM_TOP, SHADOWS_COLORS);
+		}
+
+	//	setBackgroundResource(wheelBackground);
+	}
+
+	/**
+	 * Calculates desired height for layout
+	 * 
+	 * @param layout
+	 *            the source layout
+	 * @return the desired layout height
+	 */
+	private int getDesiredHeight(LinearLayout layout) {
+		if (layout != null && layout.getChildAt(0) != null) {
+			itemHeight = layout.getChildAt(0).getMeasuredHeight();
+		}
+
+		int desired = itemHeight * visibleItems - itemHeight * ITEM_OFFSET_PERCENT / 50;
+
+		return Math.max(desired, getSuggestedMinimumHeight());
+	}
+
+	/**
+	 * Returns height of wheel item
+	 * @return the item height
+	 */
+	private int getItemHeight() {
+		if (itemHeight != 0) {
+			return itemHeight;
+		}
+
+		if (itemsLayout != null && itemsLayout.getChildAt(0) != null) {
+			itemHeight = itemsLayout.getChildAt(0).getHeight();
+			return itemHeight;
+		}
+
+		return getHeight() / visibleItems;
+	}
+
+	/**
+	 * Calculates control width and creates text layouts
+	 * @param widthSize the input layout width
+	 * @param mode the layout mode
+	 * @return the calculated control width
+	 */
+	private int calculateLayoutWidth(int widthSize, int mode) {
+		initResourcesIfNecessary();
+
+		// TODO: make it static
+		itemsLayout.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
+		itemsLayout.measure(MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.UNSPECIFIED),
+				MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
+		int width = itemsLayout.getMeasuredWidth();
+
+		if (mode == MeasureSpec.EXACTLY) {
+			width = widthSize;
+		} else {
+			width += 2 * PADDING;
+
+			// Check against our minimum width
+			width = Math.max(width, getSuggestedMinimumWidth());
+
+			if (mode == MeasureSpec.AT_MOST && widthSize < width) {
+				width = widthSize;
+			}
+		}
+
+		itemsLayout.measure(MeasureSpec.makeMeasureSpec(width - 2 * PADDING, MeasureSpec.EXACTLY),
+				MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
+
+		return width;
+	}
+
+	@Override
+	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+		int widthMode = MeasureSpec.getMode(widthMeasureSpec);
+		int heightMode = MeasureSpec.getMode(heightMeasureSpec);
+		int widthSize = MeasureSpec.getSize(widthMeasureSpec);
+		int heightSize = MeasureSpec.getSize(heightMeasureSpec);
+
+		buildViewForMeasuring();
+
+		int width = calculateLayoutWidth(widthSize, widthMode);
+
+		int height;
+		if (heightMode == MeasureSpec.EXACTLY) {
+			height = heightSize;
+		} else {
+			height = getDesiredHeight(itemsLayout);
+
+			if (heightMode == MeasureSpec.AT_MOST) {
+				height = Math.min(height, heightSize);
+			}
+		}
+
+		setMeasuredDimension(width, height);
+	}
+
+	@Override
+	protected void onLayout(boolean changed, int l, int t, int r, int b) {
+		layout(r - l, b - t);
+	}
+
+	/**
+	 * Sets layouts width and height
+	 * @param width the layout width
+	 * @param height the layout height
+	 */
+	private void layout(int width, int height) {
+		int itemsWidth = width - 2 * PADDING;
+
+		itemsLayout.layout(0, 0, itemsWidth, height);
+	}
+
+	@Override
+	protected void onDraw(Canvas canvas) {
+		super.onDraw(canvas);
+
+		if (viewAdapter != null && viewAdapter.getItemsCount() > 0) {
+			updateView();
+
+			drawItems(canvas);
+			drawCenterRect(canvas);
+		}
+
+		if (drawShadows) drawShadows(canvas);
+	}
+
+	/**
+	 * Draws shadows on top and bottom of control
+	 * @param canvas the canvas for drawing
+	 */
+	private void drawShadows(Canvas canvas) {
+		/*/ Modified by wulianghuan 2014-11-25
+		int height = (int)(1.5 * getItemHeight());
+		//*/
+		int height = (int)(3 * getItemHeight());
+		//*/
+		topShadow.setBounds(0, 0, getWidth(), height);
+		topShadow.draw(canvas);
+
+		bottomShadow.setBounds(0, getHeight() - height, getWidth(), getHeight());
+		bottomShadow.draw(canvas);
+	}
+
+	/**
+	 * Draws items
+	 * @param canvas the canvas for drawing
+	 */
+	private void drawItems(Canvas canvas) {
+		canvas.save();
+
+		int top = (currentItem - firstItem) * getItemHeight() + (getItemHeight() - getHeight()) / 2;
+		canvas.translate(PADDING, - top + scrollingOffset);
+
+		itemsLayout.draw(canvas);
+
+		canvas.restore();
+	}
+
+	/**
+	 * Draws rect for current value
+	 * @param canvas the canvas for drawing
+	 */
+	private void drawCenterRect(Canvas canvas) {
+		int center = getHeight() / 2;
+		int offset = (int) (getItemHeight() / 2 * 1.2);
+		/*/ Remarked by wulianghuan 2014-11-27  使用自己的画线,而不是描边
+		Rect rect = new Rect(left, top, right, bottom)
+		centerDrawable.setBounds(bounds)
+		centerDrawable.setBounds(0, center - offset, getWidth(), center + offset);
+		centerDrawable.draw(canvas);
+		//*/
+
+		// TODO 画线
+		Paint paint = new Paint();
+		paint.setColor(getResources().getColor(R.color.text_title));
+		// 设置线宽
+		paint.setStrokeWidth((float) 1);
+		// 绘制上边直线
+//		canvas.drawLine(0, center - offset, getWidth(), center - offset, paint);
+		// 绘制下边直线
+		canvas.drawLine(0, center + offset, getWidth(), center + offset, paint);
+	}
+
+
+	@Override
+	public boolean onTouchEvent(MotionEvent event) {
+		if (!isEnabled() || getViewAdapter() == null) {
+			return true;
+		}
+
+		switch (event.getAction()) {
+			case MotionEvent.ACTION_MOVE:
+				if (getParent() != null) {
+					getParent().requestDisallowInterceptTouchEvent(true);
+				}
+				break;
+
+			case MotionEvent.ACTION_UP:
+				if (!isScrollingPerformed) {
+					int distance = (int) event.getY() - getHeight() / 2;
+					if (distance > 0) {
+						distance += getItemHeight() / 2;
+					} else {
+						distance -= getItemHeight() / 2;
+					}
+					int items = distance / getItemHeight();
+					if (items != 0 && isValidItemIndex(currentItem + items)) {
+						notifyClickListenersAboutClick(currentItem + items);
+					}
+				}
+				break;
+		}
+
+		return scroller.onTouchEvent(event);
+	}
+
+	/**
+	 * Scrolls the wheel
+	 * @param delta the scrolling value
+	 */
+	private void doScroll(int delta) {
+		scrollingOffset += delta;
+
+		int itemHeight = getItemHeight();
+		int count = scrollingOffset / itemHeight;
+
+		int pos = currentItem - count;
+		int itemCount = viewAdapter.getItemsCount();
+
+		int fixPos = scrollingOffset % itemHeight;
+		if (Math.abs(fixPos) <= itemHeight / 2) {
+			fixPos = 0;
+		}
+		if (isCyclic && itemCount > 0) {
+			if (fixPos > 0) {
+				pos--;
+				count++;
+			} else if (fixPos < 0) {
+				pos++;
+				count--;
+			}
+			// fix position by rotating
+			while (pos < 0) {
+				pos += itemCount;
+			}
+			pos %= itemCount;
+		} else {
+			//
+			if (pos < 0) {
+				count = currentItem;
+				pos = 0;
+			} else if (pos >= itemCount) {
+				count = currentItem - itemCount + 1;
+				pos = itemCount - 1;
+			} else if (pos > 0 && fixPos > 0) {
+				pos--;
+				count++;
+			} else if (pos < itemCount - 1 && fixPos < 0) {
+				pos++;
+				count--;
+			}
+		}
+
+		int offset = scrollingOffset;
+		if (pos != currentItem) {
+			setCurrentItem(pos, false);
+		} else {
+			invalidate();
+		}
+
+		// update offset
+		scrollingOffset = offset - count * itemHeight;
+		if (scrollingOffset > getHeight()) {
+			scrollingOffset = scrollingOffset % getHeight() + getHeight();
+		}
+	}
+
+	/**
+	 * Scroll the wheel
+	 * @param time scrolling duration
+	 */
+	public void scroll(int itemsToScroll, int time) {
+		int distance = itemsToScroll * getItemHeight() - scrollingOffset;
+		scroller.scroll(distance, time);
+	}
+
+	/**
+	 * Calculates range for wheel items
+	 * @return the items range
+	 */
+	private ItemsRange getItemsRange() {
+		if (getItemHeight() == 0) {
+			return null;
+		}
+
+		int first = currentItem;
+		int count = 1;
+
+		while (count * getItemHeight() < getHeight()) {
+			first--;
+			count += 2; // top + bottom items
+		}
+
+		if (scrollingOffset != 0) {
+			if (scrollingOffset > 0) {
+				first--;
+			}
+			count++;
+
+			// process empty items above the first or below the second
+			int emptyItems = scrollingOffset / getItemHeight();
+			first -= emptyItems;
+			count += Math.asin(emptyItems);
+		}
+		return new ItemsRange(first, count);
+	}
+
+	/**
+	 * Rebuilds wheel items if necessary. Caches all unused items.
+	 * 
+	 * @return true if items are rebuilt
+	 */
+	private boolean rebuildItems() {
+		boolean updated = false;
+		ItemsRange range = getItemsRange();
+		if (itemsLayout != null) {
+			int first = recycle.recycleItems(itemsLayout, firstItem, range);
+			updated = firstItem != first;
+			firstItem = first;
+		} else {
+			createItemsLayout();
+			updated = true;
+		}
+
+		if (!updated) {
+			updated = firstItem != range.getFirst() || itemsLayout.getChildCount() != range.getCount();
+		}
+
+		if (firstItem > range.getFirst() && firstItem <= range.getLast()) {
+			for (int i = firstItem - 1; i >= range.getFirst(); i--) {
+				if (!addViewItem(i, true)) {
+					break;
+				}
+				firstItem = i;
+			}
+		} else {
+			firstItem = range.getFirst();
+		}
+
+		int first = firstItem;
+		for (int i = itemsLayout.getChildCount(); i < range.getCount(); i++) {
+			if (!addViewItem(firstItem + i, false) && itemsLayout.getChildCount() == 0) {
+				first++;
+			}
+		}
+		firstItem = first;
+
+		return updated;
+	}
+
+	/**
+	 * Updates view. Rebuilds items and label if necessary, recalculate items sizes.
+	 */
+	private void updateView() {
+		if (rebuildItems()) {
+			calculateLayoutWidth(getWidth(), MeasureSpec.EXACTLY);
+			layout(getWidth(), getHeight());
+		}
+	}
+
+	/**
+	 * Creates item layouts if necessary
+	 */
+	private void createItemsLayout() {
+		if (itemsLayout == null) {
+			itemsLayout = new LinearLayout(getContext());
+			itemsLayout.setOrientation(LinearLayout.VERTICAL);
+		}
+	}
+
+	/**
+	 * Builds view for measuring
+	 */
+	private void buildViewForMeasuring() {
+		// clear all items
+		if (itemsLayout != null) {
+			recycle.recycleItems(itemsLayout, firstItem, new ItemsRange());
+		} else {
+			createItemsLayout();
+		}
+
+		// add views
+		int addItems = visibleItems / 2;
+		for (int i = currentItem + addItems; i >= currentItem - addItems; i--) {
+			if (addViewItem(i, true)) {
+				firstItem = i;
+			}
+		}
+	}
+
+	/**
+	 * Adds view for item to items layout
+	 * @param index the item index
+	 * @param first the flag indicates if view should be first
+	 * @return true if corresponding item exists and is added
+	 */
+	private boolean addViewItem(int index, boolean first) {
+		View view = getItemView(index);
+		if (view != null) {
+			if (first) {
+				itemsLayout.addView(view, 0);
+			} else {
+				itemsLayout.addView(view);
+			}
+
+			return true;
+		}
+
+		return false;
+	}
+
+	/**
+	 * Checks whether intem index is valid
+	 * @param index the item index
+	 * @return true if item index is not out of bounds or the wheel is cyclic
+	 */
+	private boolean isValidItemIndex(int index) {
+		return viewAdapter != null && viewAdapter.getItemsCount() > 0 &&
+				(isCyclic || index >= 0 && index < viewAdapter.getItemsCount());
+	}
+
+	/**
+	 * Returns view for specified item
+	 * @param index the item index
+	 * @return item view or empty view if index is out of bounds
+	 */
+	private View getItemView(int index) {
+		if (viewAdapter == null || viewAdapter.getItemsCount() == 0) {
+			return null;
+		}
+		int count = viewAdapter.getItemsCount();
+		if (!isValidItemIndex(index)) {
+			return viewAdapter.getEmptyItem(recycle.getEmptyItem(), itemsLayout);
+		} else {
+			while (index < 0) {
+				index = count + index;
+			}
+		}
+
+		index %= count;
+		return viewAdapter.getItem(index, recycle.getItem(), itemsLayout);
+	}
+
+	/**
+	 * Stops scrolling
+	 */
+	public void stopScrolling() {
+		scroller.stopScrolling();
+	}
+}

+ 59 - 0
app/src/main/java/com/quansu/heifengwuliu/view/timeview/adapter/AbstractWheelAdapter.java

@@ -0,0 +1,59 @@
+
+package com.quansu.heifengwuliu.view.timeview.adapter;
+
+import android.database.DataSetObserver;
+import android.view.View;
+import android.view.ViewGroup;
+
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Abstract Wheel adapter.
+ */
+public abstract class AbstractWheelAdapter implements WheelTimeViewAdapter {
+    // Observers
+    private List<DataSetObserver> datasetObservers;
+    
+    @Override
+    public View getEmptyItem(View convertView, ViewGroup parent) {
+        return null;
+    }
+
+    @Override
+    public void registerDataSetObserver(DataSetObserver observer) {
+        if (datasetObservers == null) {
+            datasetObservers = new LinkedList<DataSetObserver>();
+        }
+        datasetObservers.add(observer);
+    }
+
+    @Override
+    public void unregisterDataSetObserver(DataSetObserver observer) {
+        if (datasetObservers != null) {
+            datasetObservers.remove(observer);
+        }
+    }
+    
+    /**
+     * Notifies observers about data changing
+     */
+    protected void notifyDataChangedEvent() {
+        if (datasetObservers != null) {
+            for (DataSetObserver observer : datasetObservers) {
+                observer.onChanged();
+            }
+        }
+    }
+    
+    /**
+     * Notifies observers about invalidating data
+     */
+    protected void notifyDataInvalidatedEvent() {
+        if (datasetObservers != null) {
+            for (DataSetObserver observer : datasetObservers) {
+                observer.onInvalidated();
+            }
+        }
+    }
+}

+ 254 - 0
app/src/main/java/com/quansu/heifengwuliu/view/timeview/adapter/AbstractWheelTextAdapter.java

@@ -0,0 +1,254 @@
+package com.quansu.heifengwuliu.view.timeview.adapter;
+
+import android.content.Context;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+/**
+ * Abstract wheel adapter provides common functionality for adapters.
+ */
+public abstract class AbstractWheelTextAdapter extends AbstractWheelAdapter {
+    
+    /** Text view resource. Used as a default view for adapter. */
+    public static final int TEXT_VIEW_ITEM_RESOURCE = -1;
+    
+    /** No resource constant. */
+    protected static final int NO_RESOURCE = 0;
+    
+    /** Default text color */
+    public static final int DEFAULT_TEXT_COLOR = 0xFF585858;
+    
+    /** Default text color */
+    public static final int LABEL_COLOR = 0xFF700070;
+    
+    /** Default text size */
+    public static final int DEFAULT_TEXT_SIZE = 18;
+    
+    // Text settings
+    private int textColor = DEFAULT_TEXT_COLOR;
+    private int textSize = DEFAULT_TEXT_SIZE;
+    
+    // Current context
+    protected Context context;
+    // Layout inflater
+    protected LayoutInflater inflater;
+    
+    // Items resources
+    protected int itemResourceId;
+    protected int itemTextResourceId;
+    
+    // Empty items resources
+    protected int emptyItemResourceId;
+	
+    /**
+     * Constructor
+     * @param context the current context
+     */
+    protected AbstractWheelTextAdapter(Context context) {
+        this(context, TEXT_VIEW_ITEM_RESOURCE);
+    }
+
+    /**
+     * Constructor
+     * @param context the current context
+     * @param itemResource the resource ID for a layout file containing a TextView to use when instantiating items views
+     */
+    protected AbstractWheelTextAdapter(Context context, int itemResource) {
+        this(context, itemResource, NO_RESOURCE);
+    }
+    
+    /**
+     * Constructor
+     * @param context the current context
+     * @param itemResource the resource ID for a layout file containing a TextView to use when instantiating items views
+     * @param itemTextResource the resource ID for a text view in the item layout
+     */
+    protected AbstractWheelTextAdapter(Context context, int itemResource, int itemTextResource) {
+        this.context = context;
+        itemResourceId = itemResource;
+        itemTextResourceId = itemTextResource;
+        
+        inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+    }
+    
+    /**
+     * Gets text color
+     * @return the text color
+     */
+    public int getTextColor() {
+        return textColor;
+    }
+    
+    /**
+     * Sets text color
+     * @param textColor the text color to set
+     */
+    public void setTextColor(int textColor) {
+        this.textColor = textColor;
+    }
+    
+    /**
+     * Gets text size
+     * @return the text size
+     */
+    public int getTextSize() {
+        return textSize;
+    }
+    
+    /**
+     * Sets text size
+     * @param textSize the text size to set
+     */
+    public void setTextSize(int textSize) {
+        this.textSize = textSize;
+    }
+    
+    /**
+     * Gets resource Id for items views
+     * @return the item resource Id
+     */
+    public int getItemResource() {
+        return itemResourceId;
+    }
+    
+    /**
+     * Sets resource Id for items views
+     * @param itemResourceId the resource Id to set
+     */
+    public void setItemResource(int itemResourceId) {
+        this.itemResourceId = itemResourceId;
+    }
+    
+    /**
+     * Gets resource Id for text view in item layout 
+     * @return the item text resource Id
+     */
+    public int getItemTextResource() {
+        return itemTextResourceId;
+    }
+    
+    /**
+     * Sets resource Id for text view in item layout 
+     * @param itemTextResourceId the item text resource Id to set
+     */
+    public void setItemTextResource(int itemTextResourceId) {
+        this.itemTextResourceId = itemTextResourceId;
+    }
+
+    /**
+     * Gets resource Id for empty items views
+     * @return the empty item resource Id
+     */
+    public int getEmptyItemResource() {
+        return emptyItemResourceId;
+    }
+
+    /**
+     * Sets resource Id for empty items views
+     * @param emptyItemResourceId the empty item resource Id to set
+     */
+    public void setEmptyItemResource(int emptyItemResourceId) {
+        this.emptyItemResourceId = emptyItemResourceId;
+    }
+    
+    
+    /**
+     * Returns text for specified item
+     * @param index the item index
+     * @return the text of specified items
+     */
+    protected abstract CharSequence getItemText(int index);
+
+    @Override
+    public View getItem(int index, View convertView, ViewGroup parent) {
+        if (index >= 0 && index < getItemsCount()) {
+            if (convertView == null) {
+                convertView = getView(itemResourceId, parent);
+            }
+            TextView textView = getTextView(convertView, itemTextResourceId);
+            if (textView != null) {
+                CharSequence text = getItemText(index);
+                if (text == null) {
+                    text = "";
+                }
+                textView.setText(text);
+    
+                if (itemResourceId == TEXT_VIEW_ITEM_RESOURCE) {
+                    configureTextView(textView);
+                }
+            }
+            return convertView;
+        }
+    	return null;
+    }
+
+    @Override
+    public View getEmptyItem(View convertView, ViewGroup parent) {
+        if (convertView == null) {
+            convertView = getView(emptyItemResourceId, parent);
+        }
+        if (emptyItemResourceId == TEXT_VIEW_ITEM_RESOURCE && convertView instanceof TextView) {
+            configureTextView((TextView)convertView);
+        }
+            
+        return convertView;
+	}
+
+    /**
+     * Configures text view. Is called for the TEXT_VIEW_ITEM_RESOURCE views.
+     * @param view the text view to be configured
+     */
+    protected void configureTextView(TextView view) {
+        view.setTextColor(textColor);
+        view.setGravity(Gravity.CENTER);
+        view.setTextSize(textSize);
+        view.setEllipsize(TextUtils.TruncateAt.END);
+        view.setLines(1);
+//        view.setCompoundDrawablePadding(20);
+//        view.setTypeface(Typeface.SANS_SERIF, Typeface.BOLD);
+    }
+    
+    /**
+     * Loads a text view from view
+     * @param view the text view or layout containing it
+     * @param textResource the text resource Id in layout
+     * @return the loaded text view
+     */
+    public TextView getTextView(View view, int textResource) {
+    	TextView text = null;
+    	try {
+            if (textResource == NO_RESOURCE && view instanceof TextView) {
+                text = (TextView) view;
+            } else if (textResource != NO_RESOURCE) {
+                text = (TextView) view.findViewById(textResource);
+            }
+        } catch (ClassCastException e) {
+            Log.e("AbstractWheelAdapter", "You must supply a resource ID for a TextView");
+            throw new IllegalStateException(
+                    "AbstractWheelAdapter requires the resource ID to be a TextView", e);
+        }
+        
+        return text;
+    }
+    
+    /**
+     * Loads view from resources
+     * @param resource the resource Id
+     * @return the loaded view or null if resource is not set
+     */
+    public View getView(int resource, ViewGroup parent) {
+        switch (resource) {
+        case NO_RESOURCE:
+            return null;
+        case TEXT_VIEW_ITEM_RESOURCE:
+            return new TextView(context);
+        default:
+            return inflater.inflate(resource, parent, false);    
+        }
+    }
+}

+ 43 - 0
app/src/main/java/com/quansu/heifengwuliu/view/timeview/adapter/ArrayWheelAdapter.java

@@ -0,0 +1,43 @@
+
+package com.quansu.heifengwuliu.view.timeview.adapter;
+
+import android.content.Context;
+
+/**
+ * The simple Array wheel adapter
+ * @param <T> the element type
+ */
+public class ArrayWheelAdapter<T> extends AbstractWheelTextAdapter {
+    
+    // items
+    private T items[];
+
+    /**
+     * Constructor
+     * @param context the current context
+     * @param items the items
+     */
+    public ArrayWheelAdapter(Context context, T items[]) {
+        super(context);
+        
+        //setEmptyItemResource(TEXT_VIEW_ITEM_RESOURCE);
+        this.items = items;
+    }
+    
+    @Override
+    public CharSequence getItemText(int index) {
+        if (index >= 0 && index < items.length) {
+            T item = items[index];
+            if (item instanceof CharSequence) {
+                return (CharSequence) item;
+            }
+            return item.toString();
+        }
+        return null;
+    }
+
+    @Override
+    public int getItemsCount() {
+        return items.length;
+    }
+}

+ 121 - 0
app/src/main/java/com/quansu/heifengwuliu/view/timeview/adapter/TimeNumericWheelAdapter.java

@@ -0,0 +1,121 @@
+
+package com.quansu.heifengwuliu.view.timeview.adapter;
+
+import android.content.Context;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+/**
+ * Numeric Wheel adapter.
+ */
+public class TimeNumericWheelAdapter extends AbstractWheelTextAdapter {
+    
+    /** The default min value */
+    public static final int DEFAULT_MAX_VALUE = 9;
+
+    /** The default max value */
+    private static final int DEFAULT_MIN_VALUE = 0;
+    
+    // Values
+    private int minValue;
+    private int maxValue;
+    
+    // format
+    private String format;
+    
+    private String label;
+
+    private int multiple;
+    
+    /**
+     * Constructor
+     * @param context the current context
+     */
+    public TimeNumericWheelAdapter(Context context) {
+        this(context, DEFAULT_MIN_VALUE, DEFAULT_MAX_VALUE);
+    }
+
+    /**
+     * Constructor
+     * @param context the current context
+     * @param minValue the wheel min value
+     * @param maxValue the wheel max value
+     */
+    public TimeNumericWheelAdapter(Context context, int minValue, int maxValue) {
+        this(context, minValue, maxValue, null);
+    }
+
+    /**
+     * Constructor
+     * @param context the current context
+     * @param minValue the wheel min value
+     * @param maxValue the wheel max value
+     * @param format the format string
+     */
+    public TimeNumericWheelAdapter(Context context, int minValue, int maxValue, String format) {
+        super(context);
+        
+        this.minValue = minValue;
+        this.maxValue = maxValue;
+        this.format = format;
+    }
+
+    public TimeNumericWheelAdapter(Context context, int minValue, int maxValue, String format, int multiple) {
+        super(context);
+
+        this.minValue = minValue;
+        this.maxValue = maxValue;
+        this.format = format;
+        this.multiple = multiple;
+    }
+
+    @Override
+    public CharSequence getItemText(int index) {
+        if (index >= 0 && index < getItemsCount()) {
+
+            int value = 0;
+            if (multiple != 0){
+                value = minValue + index * multiple;
+            }else{
+                value = minValue + index;
+            }
+//            int value = minValue + index;
+            return format != null ? String.format(format, value) : Integer.toString(value);
+        }
+        return null;
+    }
+
+    @Override
+    public int getItemsCount() {
+        return maxValue - minValue + 1;
+    }
+    
+    @Override
+    public View getItem(int index, View convertView, ViewGroup parent) {
+        if (index >= 0 && index < getItemsCount()) {
+            if (convertView == null) {
+                convertView = getView(itemResourceId, parent);
+            }
+            TextView textView = getTextView(convertView, itemTextResourceId);
+            if (textView != null) {
+                CharSequence text = getItemText(index);
+                if (text == null) {
+                    text = "";
+                }
+                textView.setText(text+label);
+                textView.setPadding(0,3,0,3);
+                if (itemResourceId == TEXT_VIEW_ITEM_RESOURCE) {
+                    configureTextView(textView);
+                }
+            }
+            return convertView;
+        }
+    	return null;
+    }
+
+	public void setLabel(String label) {
+		this.label=label;
+	}    
+	
+}

+ 51 - 0
app/src/main/java/com/quansu/heifengwuliu/view/timeview/adapter/WheelTimeViewAdapter.java

@@ -0,0 +1,51 @@
+
+package com.quansu.heifengwuliu.view.timeview.adapter;
+
+import android.database.DataSetObserver;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * Wheel items adapter interface
+ */
+public interface WheelTimeViewAdapter {
+	
+	/**
+	 * Gets items count
+	 * @return the count of wheel items
+	 */
+	public int getItemsCount();
+	
+	/**
+	 * Get a View that displays the data at the specified position in the data set
+	 * 
+	 * @param index the item index
+	 * @param convertView the old view to reuse if possible
+	 * @param parent the parent that this view will eventually be attached to
+	 * @return the wheel item View
+	 */
+	public View getItem(int index, View convertView, ViewGroup parent);
+
+	/**
+	 * Get a View that displays an empty wheel item placed before the first or after
+	 * the last wheel item.
+	 * 
+	 * @param convertView the old view to reuse if possible
+     * @param parent the parent that this view will eventually be attached to
+	 * @return the empty item View
+	 */
+	public View getEmptyItem(View convertView, ViewGroup parent);
+	
+	/**
+	 * Register an observer that is called when changes happen to the data used by this adapter.
+	 * @param observer the observer to be registered
+	 */
+	public void registerDataSetObserver(DataSetObserver observer);
+	
+	/**
+	 * Unregister an observer that has previously been registered
+	 * @param observer the observer to be unregistered
+	 */
+	void unregisterDataSetObserver(DataSetObserver observer);
+	
+}

+ 220 - 0
app/src/main/java/com/quansu/heifengwuliu/widget/TimeLeftView.kt

@@ -0,0 +1,220 @@
+package com.quansu.heifengwuliu.widget
+
+import android.content.Context
+import android.util.AttributeSet
+import android.view.LayoutInflater
+import androidx.databinding.DataBindingUtil
+import com.quansu.heifengwuliu.R
+import com.quansu.heifengwuliu.databinding.FragmentTimeLeftBinding
+import com.quansu.heifengwuliu.inte.ChoiceListData
+import com.quansu.heifengwuliu.view.timeview.OnWheelTimeScrollListener
+import com.quansu.heifengwuliu.view.timeview.WheelTimeView
+import com.quansu.heifengwuliu.view.timeview.adapter.TimeNumericWheelAdapter
+import com.ysnows.base.view.BView
+import com.ysnows.base.view.BaseView
+import java.lang.String
+import java.util.*
+
+/**
+ *Created by shihuiyun
+ *on 2020/11/23
+ */
+class TimeLeftView(context: Context, attrs: AttributeSet) :BaseLinearLayout(context, attrs) {
+
+    private var binding: FragmentTimeLeftBinding? = null
+
+    private var view: BView? = null
+
+    init {
+        init(context)
+
+    }
+
+    private fun init(context: Context) {
+        if (context is BaseView) {
+            view = context as BView
+        }
+        binding = DataBindingUtil.inflate(LayoutInflater.from(context), R.layout.fragment_time_left, this, true)
+        setDate()
+    }
+
+
+
+    var choiceTimeLeftData: ChoiceListData? =null
+    fun  setCallBack(choiceData: ChoiceListData){
+        this.choiceTimeLeftData=choiceData
+
+        if(null!=choiceData){
+
+            val c: Calendar = Calendar.getInstance()
+            val curYear: Int = c.get(Calendar.YEAR)
+
+
+            val time = String.format(
+                    Locale.CHINA, "%04d-%02d-%02d", binding!!.year.currentItem + curYear,
+                    binding!!.month.currentItem + 1, binding!!.day.currentItem + 1,
+            )
+            choiceData.onRestuse("1",time)
+
+        }
+    }
+
+    fun setDate(){
+        val c: Calendar = Calendar.getInstance()
+        val curYear: Int = c.get(Calendar.YEAR)
+        val curMonth: Int = c.get(Calendar.MONTH) + 1 //通过Calendar算出的月数要+1
+
+        val curDate: Int = c.get(Calendar.DATE)
+
+        initYear()
+        initMonth()
+        initDay(curYear, curMonth)
+
+        binding!!.year.currentItem = 0
+        binding!!.month.currentItem = curMonth - 1
+        binding!!.day.currentItem = curDate - 1
+        binding!!.year.visibleItems = 7
+        binding!!.month.visibleItems = 7
+        binding!!.day.visibleItems = 7
+
+
+    }
+
+    /**
+     * 初始化年
+     */
+    private fun initYear() {
+        val c: Calendar = Calendar.getInstance()
+        val curYear: Int = c.get(Calendar.YEAR)
+
+        val numericWheelAdapter = TimeNumericWheelAdapter(context, curYear, 2050)
+        numericWheelAdapter.setLabel(" 年")
+        numericWheelAdapter.textSize = 18
+        numericWheelAdapter.textColor = resources.getColor(R.color.pay_off)
+
+        binding!!.year.viewAdapter = numericWheelAdapter
+        binding!!.year.isCyclic = true
+        binding!!.year.addScrollingListener(object : OnWheelTimeScrollListener {
+            override fun onScrollingStarted(wheel: WheelTimeView?) {
+
+            }
+
+            override fun onScrollingFinished(wheel: WheelTimeView?) {
+
+                val c: Calendar = Calendar.getInstance()
+                val curYear: Int = c.get(Calendar.YEAR)
+
+                val time = String.format(
+                        Locale.CHINA, "%04d-%02d-%02d", binding!!.year.currentItem + curYear,
+                        binding!!.month.currentItem + 1, binding!!.day.currentItem + 1,
+                )
+
+                if(null!=choiceTimeLeftData){
+
+                    choiceTimeLeftData!!.onRestuse("1",time)
+
+                }
+
+            }
+
+        })
+    }
+    /**
+     * 初始化月
+     */
+    private fun initMonth() {
+        val numericWheelAdapter = TimeNumericWheelAdapter(context, 1, 12, "%02d")
+        numericWheelAdapter.setLabel(" 月")
+        numericWheelAdapter.textSize = 18
+        numericWheelAdapter.textColor= resources.getColor(R.color.pay_off)
+        binding!!.month.viewAdapter = numericWheelAdapter
+        binding!!.month.isCyclic = true
+        binding!!.month.addScrollingListener(object : OnWheelTimeScrollListener {
+            override fun onScrollingStarted(wheel: WheelTimeView?) {
+
+            }
+
+            override fun onScrollingFinished(wheel: WheelTimeView?) {
+
+                val c: Calendar = Calendar.getInstance()
+                val curYear: Int = c.get(Calendar.YEAR)
+
+                val time = String.format(
+                        Locale.CHINA, "%04d-%02d-%02d", binding!!.year.currentItem + curYear,
+                        binding!!.month.currentItem + 1, binding!!.day.currentItem + 1,
+                )
+                if(null!=choiceTimeLeftData){
+
+                    choiceTimeLeftData!!.onRestuse("1",time)
+
+                }
+
+
+            }
+
+        })
+
+    }
+
+    /**
+     * 初始化天
+     */
+    private fun initDay(arg1: Int, arg2: Int) {
+        val numericWheelAdapter = TimeNumericWheelAdapter(context, 1, getDay(arg1, arg2), "%02d")
+        numericWheelAdapter.setLabel(" 日")
+        numericWheelAdapter.textSize = 18
+        numericWheelAdapter.textColor= resources.getColor(R.color.pay_off)
+        binding!!.day.viewAdapter = numericWheelAdapter
+        binding!!.day.isCyclic = true
+
+        binding!!.day.addScrollingListener(object : OnWheelTimeScrollListener {
+            override fun onScrollingStarted(wheel: WheelTimeView?) {
+
+            }
+
+            override fun onScrollingFinished(wheel: WheelTimeView?) {
+
+                val c: Calendar = Calendar.getInstance()
+                val curYear: Int = c.get(Calendar.YEAR)
+
+                val time = String.format(
+                        Locale.CHINA, "%04d-%02d-%02d", binding!!.year.currentItem + curYear,
+                        binding!!.month.currentItem + 1, binding!!.day.currentItem + 1,
+                )
+                if(null!=choiceTimeLeftData){
+
+                    choiceTimeLeftData!!.onRestuse("1",time)
+
+                }
+
+
+            }
+
+        })
+
+    }
+
+    /**
+     *
+     * @param year
+     * @param month
+     * @return
+     */
+    private fun getDay(year: Int, month: Int): Int {
+        var day = 30
+        var flag = false
+        flag = when (year % 4) {
+            0 -> true
+            else -> false
+        }
+        day = when (month) {
+            1, 3, 5, 7, 8, 10, 12 -> 31
+            2 -> if (flag) 29 else 28
+            else -> 30
+        }
+        return day
+    }
+
+
+
+}

+ 194 - 0
app/src/main/java/com/quansu/heifengwuliu/widget/TimeRightView.kt

@@ -0,0 +1,194 @@
+package com.quansu.heifengwuliu.widget
+
+import android.content.Context
+import android.util.AttributeSet
+import android.view.LayoutInflater
+import androidx.databinding.DataBindingUtil
+import com.quansu.heifengwuliu.R
+import com.quansu.heifengwuliu.databinding.FragmentTimeRightBinding
+import com.quansu.heifengwuliu.inte.ChoiceListData
+import com.quansu.heifengwuliu.view.timeview.OnWheelTimeScrollListener
+import com.quansu.heifengwuliu.view.timeview.WheelTimeView
+import com.quansu.heifengwuliu.view.timeview.adapter.TimeNumericWheelAdapter
+import com.ysnows.base.view.BView
+import com.ysnows.base.view.BaseView
+import java.lang.String
+import java.util.*
+
+/**
+ *Created by shihuiyun
+ *on 2020/11/23
+ */
+class TimeRightView(context: Context, attrs: AttributeSet) :BaseLinearLayout(context,attrs) {
+
+    private var binding: FragmentTimeRightBinding? = null
+
+    private var view: BView? = null
+
+    init {
+        init(context)
+
+    }
+
+    private fun init(context: Context) {
+        if (context is BaseView) {
+            view = context as BView
+        }
+        binding = DataBindingUtil.inflate(LayoutInflater.from(context), R.layout.fragment_time_right, this, true)
+        setTime()
+    }
+
+
+
+    var choiceTimeRightData: ChoiceListData? =null
+    fun  setCallBack(choiceData: ChoiceListData){
+        this.choiceTimeRightData=choiceData
+
+//        if(null!=choiceData){
+//
+//            val time = String.format(
+//                    Locale.CHINA, "%02d-%02d",  binding!!.hour.currentItem, binding!!.mins.currentItem
+//            )
+//            choiceData.onRestuse("2",time)
+//
+//        }
+    }
+
+
+    fun getTime(): kotlin.String {
+
+        return  String.format(
+                Locale.CHINA, "%02d:%02d:%02d",
+                binding!!.hour.currentItem, binding!!.mins.currentItem,
+                binding!!.second.currentItem
+        )
+    }
+
+    private fun setTime() {
+        val c: Calendar = Calendar.getInstance()
+        val curHour: Int = c.get(Calendar.HOUR_OF_DAY)
+        val curMin: Int = c.get(Calendar.MINUTE)
+        val curSecond: Int = c.get(Calendar.SECOND)
+
+        initHour()
+        initMins()
+        initSecond()
+        // 设置当前时间
+        binding!!.hour.currentItem = curHour
+        binding!!.mins.currentItem = curMin
+        binding!!.second.currentItem = curSecond
+        binding!!.hour.visibleItems = 7
+        binding!!.mins.visibleItems = 7
+        binding!!.second.visibleItems = 7
+    }
+
+    /**
+     * 初始化时
+     */
+    private fun initHour() {
+        val numericWheelAdapter = TimeNumericWheelAdapter(context, 0, 23, "%02d")
+        numericWheelAdapter.setLabel(" 时")
+        numericWheelAdapter.textSize = 18
+        numericWheelAdapter.textColor= resources.getColor(R.color.pay_off)
+        binding!!.hour.viewAdapter = numericWheelAdapter
+        binding!!.hour.isCyclic = true
+
+        binding!!.hour.addScrollingListener(object : OnWheelTimeScrollListener {
+            override fun onScrollingStarted(wheel: WheelTimeView?) {
+
+            }
+
+            override fun onScrollingFinished(wheel: WheelTimeView?) {
+                val time = String.format(
+                        Locale.CHINA, "%02d:%02d:%02d",
+                        binding!!.hour.currentItem, binding!!.mins.currentItem,
+                        binding!!.second.currentItem
+                )
+
+                if(null!=choiceTimeRightData){
+
+                    choiceTimeRightData!!.onRestuse("2",time)
+
+                }
+
+            }
+
+        })
+
+
+    }
+    /**
+     * 初始化分
+     */
+    private fun initMins() {
+
+        val numericWheelAdapter = TimeNumericWheelAdapter(context, 0, 59, "%02d")
+        numericWheelAdapter.setLabel(" 分")
+        numericWheelAdapter.textSize = 18
+        numericWheelAdapter.textColor= resources.getColor(R.color.pay_off)
+        binding!!.mins.viewAdapter = numericWheelAdapter
+        binding!!.mins.isCyclic = true
+
+        binding!!.mins.addScrollingListener(object : OnWheelTimeScrollListener {
+            override fun onScrollingStarted(wheel: WheelTimeView?) {
+
+            }
+
+            override fun onScrollingFinished(wheel: WheelTimeView?) {
+                val time = String.format(
+                        Locale.CHINA, "%02d:%02d:%02d",
+                        binding!!.hour.currentItem, binding!!.mins.currentItem,
+                        binding!!.second.currentItem
+                )
+                if(null!=choiceTimeRightData){
+
+                    choiceTimeRightData!!.onRestuse("2",time)
+
+                }
+
+            }
+
+        })
+
+
+    }
+
+
+    /**
+     * 初始化秒
+     */
+    private fun initSecond() {
+
+        val numericWheelAdapter = TimeNumericWheelAdapter(context, 0, 59, "%02d")
+        numericWheelAdapter.setLabel(" 秒")
+        numericWheelAdapter.textSize = 18
+        numericWheelAdapter.textColor= resources.getColor(R.color.pay_off)
+        binding!!.second.viewAdapter = numericWheelAdapter
+        binding!!.second.isCyclic = true
+
+        binding!!.second.addScrollingListener(object : OnWheelTimeScrollListener {
+            override fun onScrollingStarted(wheel: WheelTimeView?) {
+
+            }
+
+            override fun onScrollingFinished(wheel: WheelTimeView?) {
+                val time = String.format(
+                        Locale.CHINA, "%02d:%02d:%02d",
+                        binding!!.hour.currentItem, binding!!.mins.currentItem,
+                        binding!!.second.currentItem
+                )
+                if(null!=choiceTimeRightData){
+
+                    choiceTimeRightData!!.onRestuse("2",time)
+
+                }
+
+            }
+
+        })
+
+
+    }
+
+
+}

+ 31 - 0
app/src/main/res/drawable/wheel_bg.xml

@@ -0,0 +1,31 @@
+<?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="#fff"
+                android:endColor="#fff"
+                android:startColor="#fff" />
+
+            <stroke
+                android:width="1dp"
+                android:color="#00000000" />
+        </shape>
+    </item>
+    <item
+        android:bottom="1dp"
+        android:left="4dp"
+        android:right="4dp"
+        android:top="1dp">
+        <shape android:shape="rectangle" >
+            <gradient
+                android:angle="0"
+                android:centerColor="#FFF"
+                android:endColor="#fff"
+                android:startColor="#fff" />
+        </shape>
+    </item>
+
+</layer-list>

+ 12 - 0
app/src/main/res/drawable/wheel_val_time.xml

@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+	<gradient
+		android:startColor="#10000000"
+		android:centerColor="#00000000"
+		android:endColor="#10000000"
+		android:angle="0" />
+
+	<stroke android:width="1dp" android:color="#00000000" /> 
+</shape>

+ 2 - 0
app/src/main/res/layout/fragment_ownersingle.xml

@@ -22,6 +22,7 @@
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:background="@color/white"
+            android:visibility="gone"
             android:orientation="vertical">
 
             <TextView
@@ -37,6 +38,7 @@
             android:layout_height="50dp"
             android:background="@color/white"
             android:gravity="center"
+            android:visibility="gone"
             android:orientation="horizontal"
             >
 

+ 43 - 57
app/src/main/res/layout/fragment_time_left.xml

@@ -1,71 +1,57 @@
 <?xml version="1.0" encoding="utf-8"?>
 <layout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto" >
+    xmlns:app="http://schemas.android.com/apk/res-auto">
 
-    <data >
-        <variable
-            name="vm"
-            type="com.quansu.heifengwuliu.vmodel.OwnerImgVModel" />
+    <data>
 
-    </data >
 
-    <LinearLayout
+    </data>
+
+    <LinearLayout xmlns:tools="http://schemas.android.com/tools"
         android:layout_width="match_parent"
-        android:layout_height="match_parent"
+        android:layout_height="wrap_content"
         android:gravity="center"
-        xmlns:tools="http://schemas.android.com/tools"
-        android:orientation="horizontal" >
-
-        <ImageView
-            android:id="@+id/img"
-            android:layout_width="128dp"
-            android:src="@drawable/img_bg"
-            android:scaleType="centerCrop"
-            app:url="@{vm.url}"
-            android:layout_height="58dp">
+        android:orientation="vertical">
 
-        </ImageView>
 
         <LinearLayout
-            android:layout_width="wrap_content"
-            android:orientation="vertical"
-            android:layout_marginStart="34dp"
-            android:layout_height="wrap_content">
-
-            <TextView
-                android:id="@+id/tv_weight"
-                android:layout_width="wrap_content"
-                android:text="@{vm.weight}"
-                android:textSize="12sp"
-                android:textColor="#545556"
-                android:layout_height="wrap_content"/>
-
-            <TextView
-                android:id="@+id/tv_length"
-                android:layout_width="wrap_content"
-                tools:text="长宽高:5.2*2.1*2米"
-                android:text="@{vm.name}"
-                android:textSize="12sp"
-                android:layout_marginTop="4dp"
-                android:textColor="#545556"
-                android:layout_height="wrap_content"/>
-            <TextView
-                android:id="@+id/tv_volume"
-                android:layout_width="wrap_content"
-                tools:text="载货体积:21.8方"
-                android:textSize="12sp"
-                android:text="@{vm.volume}"
-                android:layout_marginTop="4dp"
-                android:textColor="#545556"
-                android:layout_height="wrap_content"/>
-<!--                            android:text="@{@string/cargo_volume+item.weight}"
--->
-
-
-
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal"
+            android:paddingBottom="20dp"
+            android:background="@color/white"
+            android:layout_weight="1"
+            android:paddingTop="10dp">
+
+            <com.quansu.heifengwuliu.view.timeview.WheelTimeView
+                android:id="@+id/year"
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginBottom="10dip"
+                android:layout_marginLeft="5dip"
+                android:layout_marginTop="10dip"
+                android:layout_weight="0.8" />
+
+            <com.quansu.heifengwuliu.view.timeview.WheelTimeView
+                android:id="@+id/month"
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginBottom="10dip"
+                android:layout_marginTop="10dip"
+                android:layout_weight="1" />
+
+            <com.quansu.heifengwuliu.view.timeview.WheelTimeView
+                android:id="@+id/day"
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginBottom="10dip"
+                android:layout_marginRight="5dip"
+                android:layout_marginTop="10dip"
+                android:layout_weight="1" />
         </LinearLayout>
 
 
 
-    </LinearLayout >
-</layout >
+
+    </LinearLayout>
+</layout>

+ 34 - 57
app/src/main/res/layout/fragment_time_right.xml

@@ -1,71 +1,48 @@
 <?xml version="1.0" encoding="utf-8"?>
 <layout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto" >
+    xmlns:app="http://schemas.android.com/apk/res-auto">
 
-    <data >
-        <variable
-            name="vm"
-            type="com.quansu.heifengwuliu.vmodel.OwnerImgVModel" />
+    <data>
 
-    </data >
 
-    <LinearLayout
+
+    </data>
+
+    <LinearLayout xmlns:tools="http://schemas.android.com/tools"
         android:layout_width="match_parent"
-        android:layout_height="match_parent"
+        android:layout_height="wrap_content"
         android:gravity="center"
-        xmlns:tools="http://schemas.android.com/tools"
-        android:orientation="horizontal" >
+        android:orientation="vertical">
 
-        <ImageView
-            android:id="@+id/img"
-            android:layout_width="128dp"
-            android:src="@drawable/img_bg"
-            android:scaleType="centerCrop"
-            app:url="@{vm.url}"
-            android:layout_height="58dp">
 
-        </ImageView>
 
         <LinearLayout
-            android:layout_width="wrap_content"
-            android:orientation="vertical"
-            android:layout_marginStart="34dp"
-            android:layout_height="wrap_content">
-
-            <TextView
-                android:id="@+id/tv_weight"
-                android:layout_width="wrap_content"
-                android:text="@{vm.weight}"
-                android:textSize="12sp"
-                android:textColor="#545556"
-                android:layout_height="wrap_content"/>
-
-            <TextView
-                android:id="@+id/tv_length"
-                android:layout_width="wrap_content"
-                tools:text="长宽高:5.2*2.1*2米"
-                android:text="@{vm.name}"
-                android:textSize="12sp"
-                android:layout_marginTop="4dp"
-                android:textColor="#545556"
-                android:layout_height="wrap_content"/>
-            <TextView
-                android:id="@+id/tv_volume"
-                android:layout_width="wrap_content"
-                tools:text="载货体积:21.8方"
-                android:textSize="12sp"
-                android:text="@{vm.volume}"
-                android:layout_marginTop="4dp"
-                android:textColor="#545556"
-                android:layout_height="wrap_content"/>
-<!--                            android:text="@{@string/cargo_volume+item.weight}"
--->
-
-
-
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:background="@color/white"
+            android:orientation="horizontal"
+            android:paddingBottom="20dp">
+
+            <com.quansu.heifengwuliu.view.timeview.WheelTimeView
+                android:id="@+id/hour"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_weight="1" />
+
+            <com.quansu.heifengwuliu.view.timeview.WheelTimeView
+                android:id="@+id/mins"
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"
+                android:layout_weight="1" />
+
+            <com.quansu.heifengwuliu.view.timeview.WheelTimeView
+                android:id="@+id/second"
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"
+                android:layout_weight="1" />
         </LinearLayout>
 
 
-
-    </LinearLayout >
-</layout >
+    </LinearLayout>
+</layout>

+ 84 - 27
app/src/main/res/layout/item_chose_time.xml

@@ -3,16 +3,20 @@
     xmlns:app="http://schemas.android.com/apk/res-auto"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:gravity="center"
     xmlns:tools="http://schemas.android.com/tools"
     android:orientation="vertical">
 
+    <LinearLayout
+        android:id="@+id/ll"
+        android:layout_width="match_parent"
+        android:layout_weight="1"
+        android:orientation="vertical"
+        android:layout_height="0dp"/>
+
 
     <com.qmuiteam.qmui.widget.roundwidget.QMUIRoundLinearLayout
         android:layout_width="match_parent"
-        android:layout_height="260dp"
-        android:layout_marginStart="27dp"
-        android:layout_marginEnd="27dp"
+        android:layout_height="wrap_content"
         android:background="@color/white"
         android:gravity="center_horizontal"
         android:orientation="vertical"
@@ -31,16 +35,6 @@
             android:textSize="17sp" />
 
 
-        <TextView
-            android:id="@+id/tv_time"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_centerHorizontal="true"
-            android:layout_marginTop="10dp"
-            android:layout_marginBottom="10dp"
-            android:textColor="#ECB108"
-            tools:text="选择时间"
-            android:textSize="14sp" />
 
 
         <LinearLayout
@@ -49,13 +43,69 @@
             android:gravity="center_vertical"
             android:orientation="horizontal">
 
-            <com.qmuiteam.qmui.widget.tab.QMUITabSegment
-                android:id="@+id/tabs"
+            <LinearLayout
                 android:layout_width="0dp"
-                android:layout_height="43dp"
                 android:layout_weight="1"
-                android:background="@color/white"
-                android:textSize="12sp" />
+                android:orientation="horizontal"
+                android:layout_height="wrap_content">
+
+                <LinearLayout
+                    android:id="@+id/ll_data"
+                    android:layout_width="wrap_content"
+                    android:orientation="vertical"
+                    android:layout_marginLeft="20dp"
+                    android:gravity="center"
+                    android:layout_height="wrap_content">
+
+                    <TextView
+                        android:id="@+id/tv_data"
+                        android:text="日期"
+                        android:layout_marginTop="10dp"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"/>
+                    <View
+                        android:id="@+id/line_data"
+                        android:layout_width="20dp"
+                        android:background="#ECB108"
+                        android:layout_marginTop="10dp"
+                        android:layout_height="1dp"/>
+
+                </LinearLayout>
+
+
+                <LinearLayout
+                    android:id="@+id/ll_time"
+                    android:layout_width="wrap_content"
+                    android:orientation="vertical"
+                    android:layout_marginLeft="20dp"
+                    android:gravity="center"
+                    android:layout_height="wrap_content">
+
+                    <TextView
+                        android:id="@+id/tv_time"
+                        android:text="时间"
+                        android:layout_width="wrap_content"
+                        android:layout_marginTop="10dp"
+                        android:layout_height="wrap_content"/>
+                    <View
+                        android:id="@+id/line_time"
+                        android:layout_width="20dp"
+                        android:background="#ECB108"
+                        android:visibility="invisible"
+                        android:layout_marginTop="10dp"
+                        android:layout_height="1dp"/>
+
+                </LinearLayout>
+
+            </LinearLayout>
+
+<!--            <com.qmuiteam.qmui.widget.tab.QMUITabSegment-->
+<!--                android:id="@+id/tabs"-->
+<!--                android:layout_width="0dp"-->
+<!--                android:layout_height="43dp"-->
+<!--                android:layout_weight="1"-->
+<!--                android:background="@color/white"-->
+<!--                android:textSize="12sp" />-->
 
             <TextView
                 android:id="@+id/tv_sure"
@@ -73,19 +123,26 @@
             android:layout_height="1dp"
             android:background="#E3E4E5" />
 
-        <LinearLayout
+
+        <FrameLayout
             android:layout_width="match_parent"
-            android:layout_height="match_parent"
+            android:orientation="vertical"
             android:background="@color/white"
-            android:gravity="center_vertical"
-            android:orientation="horizontal">
+            android:layout_height="wrap_content">
+
 
-            <com.qmuiteam.qmui.widget.QMUIViewPager
-                android:id="@+id/qm_view_pager"
+            <com.quansu.heifengwuliu.widget.TimeRightView
+                android:id="@+id/time_right"
                 android:layout_width="match_parent"
-                android:layout_height="match_parent" />
+                android:layout_height="wrap_content"/>
+            <com.quansu.heifengwuliu.widget.TimeLeftView
+                android:id="@+id/time_left"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"/>
+
+        </FrameLayout>
+
 
-        </LinearLayout>
 
 
     </com.qmuiteam.qmui.widget.roundwidget.QMUIRoundLinearLayout>

+ 3 - 0
app/src/main/res/values/colors.xml

@@ -237,4 +237,7 @@
     <color name="insure_text_off">#F6C553</color>
 
 
+    <color name="province_line_border">#D0D0D0</color>
+
+
 </resources >