1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > android日历价格控件 Android 自定义价格日历控件

android日历价格控件 Android 自定义价格日历控件

时间:2021-04-02 20:36:43

相关推荐

android日历价格控件 Android 自定义价格日历控件

介绍

上个星期项目有一个日历价格的需求,类似一个商品在不同的日期价格可能会不同,由于时间给得特别紧所以打算找个合适的开源项目进行修改。参考了网上大多数是通过继承view直接draw一个monthView,然后通过listview来实现monthView的复用。但是继承view通过draw来实现月份日历比较麻烦,如果需要修改样式或者添加额外的信息会比较麻烦,所以为什么不用gridview来实现月份的显示呢?这样monthview的每个布局都是写在xml里的,别人参考你的改起来也方便,并且大多于自己的需求不符合,所以自己实现了一个价格日历,这里分享出来给大家参考。先贴一下效果图

实现思路

前面提到了用gridView来显示月份,要实现日历肯定有很多月份,所以我们用viewPager+gridView来实现,这里我们不仅要实现效果 还要以后遇到类似的功能只需要简单使用而不是重写,所以考虑自定义view中的组合类型。关于自定义view我之前有多篇文章讲到,概念性的东西就不提了,直接开始。

具体实现

组合控件其实就是将多个控件组合在一个控件里并且在该控件中实现一些交互和处理,是为了封装一些内部特性,方便直接使用。

步骤1 获取内部控件

。上面我们提到用viewPager+gridView来实现,当然还有一个显示月份的textview和两个button。那么第一步就是获取到这些控件。声明变量并在onFinishInflate() 方法中获取。

代码如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47public class CommonCalendarView extends FrameLayout implements View.OnClickListener {

private ViewPager mViewPager;

private TextView mMonthTv;

private Context mContext;

private android.widget.ImageButton mLeftMonthBtn;

private android.widget.ImageButton mRightMonthBtn;

public CommonCalendarView(Context context) {

this(context,null);

}

public CommonCalendarView(Context context, AttributeSet attrs) {

this(context, attrs,0);

}

public CommonCalendarView(Context context, AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);

mContext = context;

}

@Override

protected void onFinishInflate() {

super.onFinishInflate();

View view = LayoutInflater.from(mContext).inflate(R.layout.activity_page_calendar_price,this,true);

this.mViewPager = (ViewPager) view.findViewById(R.id.viewPager);

this.mRightMonthBtn = (ImageButton) view.findViewById(R.id.right_month_btn);

this.mMonthTv = (TextView) view.findViewById(R.id.month_tv);

this.mLeftMonthBtn = (ImageButton) view.findViewById(R.id.left_month_btn);

this.mLeftMonthBtn.setOnClickListener(this);

this.mRightMonthBtn.setOnClickListener(this);

}

@Override

public void onClick(View v) {

switch (v.getId()){

case R.id.left_month_btn:

mViewPager.setCurrentItem(mViewPager.getCurrentItem()-1,true);

break;

case R.id.right_month_btn:

mViewPager.setCurrentItem(mViewPager.getCurrentItem()+1,true);

break;

}

}

}

代码大家肯定一看就知道,获取控件,为左右两个按钮设置点击实现。直接调用viewPager的setCurrentItem();

步骤2 为ViewPager设置适配器显示年月

有了基本的控件以后那么我们还需要用来显示数据,从使用者的角度来说我可能只想告诉你最大最小日期,或者最大年份就可以了。这里提供一个接口获取最大年份并且声明最大最小日期变量,代码如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33...

private DatePickerController mController;

private CalendarAdapter adapter;

private Date maxDate;

private Date minDate;

public void setMaxDate(Date maxDate) {

this.maxDate = maxDate;

}

public void setMinDate(Date minDate) {

this.minDate = minDate;

}

public interface DatePickerController {

int getMaxYear();

void onDayOfMonthSelected(int year, int month, int day);//日期选择

void onDayOfMonthAndDataSelected(int year,int month,int day,List obj);//日期附加信息选择

//展示其它属性(用于扩展数据日期相等时设置显示效果)

void showOtherFields(Object obj, View view, int gridItemYear, int gridItemMonth, int gridItemDay);

//获取附加信息

Map getDataSource();

}

...

为外部提供控件初始化方法用来获取数据

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62public void init(DatePickerController controller){

if (controller==null){

mController = new DatePickerController() {

@Override

public int getMaxYear() {

return DateUtils.getToYear()+1;

}

@Override

public void onDayOfMonthSelected(int year, int month, int day) {

Toast.makeText(mContext, String.format("%s-%s-%s", year,StringUtils.leftPad(String.valueOf(month),2,"0"),

StringUtils.leftPad(String.valueOf(day),2,"0")), Toast.LENGTH_SHORT).show();

}

@Override

public void onDayOfMonthAndDataSelected(int year, int month, int day, List obj) {

}

@Override

public void showOtherFields(Object obj, View view, int gridItemYear, int gridItemMonth, int gridItemDay) {

}

@Override

public Map getDataSource() {

return null;

}

};

}else{

mController = controller;

}

this.mYearMonthMap = mController.getDataSource();

adapter = new CalendarAdapter(mContext);

mViewPager.setPageTransformer(true,new DepthPageTransformer());

mViewPager.setAdapter(adapter);

if (minDate!=null){

mMonthTv.setText(String.format("%s年%s月",DateUtils.getYear(minDate), StringUtils.leftPad(String.valueOf(DateUtils.getMonth(minDate)),2,"0")));

}else{

mMonthTv.setText(String.format("%s年%s月",DateUtils.getToYear(), StringUtils.leftPad(String.valueOf(DateUtils.getToMonth()),2,"0")));

}

mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {

@Override

public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

}

@Override

public void onPageSelected(int position) {

mMonthTv.setText(adapter.getPageTitle(position));

}

@Override

public void onPageScrollStateChanged(int state) {

}

});

}

上面的代码如果用户没有提供给我们,我们默认数据源提供maxYear 为今年+1,默认点击事件实现Toast提示。

否则的话直接为controller赋值。

同时设置viewPager的adapter。

来看adapter的代码

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97class CalendarAdapter extends PagerAdapter implements AdapterView.OnItemClickListener {

protected static final int MONTHS_IN_YEAR = 12;

private final Calendar calendar = Calendar.getInstance();

private Integer firstMonth = calendar.get(Calendar.MONTH);

private LayoutInflater inflater;

private Integer lastMonth = (calendar.get(Calendar.MONTH) - 1) % MONTHS_IN_YEAR;

private Integer startYear = calendar.get(Calendar.YEAR);

public CalendarAdapter(Context context) {

inflater = LayoutInflater.from(context);

mContext = context;

if (maxDate!=null){

lastMonth = DateUtils.getMonth(maxDate)-1;

}

if (minDate!=null){

startYear = DateUtils.getYear(minDate);

firstMonth = DateUtils.getMonth(minDate)-1;

}

}

@Override

public CharSequence getPageTitle(int position) {

int year = position / MONTHS_IN_YEAR + startYear + ((firstMonth + (position % MONTHS_IN_YEAR)) / MONTHS_IN_YEAR);

int month = (firstMonth + (position % MONTHS_IN_YEAR)) % MONTHS_IN_YEAR;

return String.format("%s年%s月",year, StringUtils.leftPad(String.valueOf(month+1),2,"0"));

}

@Override

public int getCount() {

int maxYear = mController.getMaxYear();

int minYear = calendar.get(Calendar.YEAR) ;

if (maxDate!=null){

maxYear = DateUtils.getYear(maxDate);

}

if (minDate!=null){

minYear = DateUtils.getYear(minDate);

}

int itemCount = (maxYear-minYear+1) * MONTHS_IN_YEAR;

if (firstMonth != -1)

itemCount -= firstMonth;

if (lastMonth != -1)

itemCount -= (MONTHS_IN_YEAR - lastMonth) - 1;

return itemCount;

}

@Override

public Object instantiateItem(ViewGroup container, int position) {

GridView mGridView = mViewMap.get(position);

if (mGridView ==null){

mGridView = (GridView) inflater.inflate(R.layout.item_page_month_day, container, false);

mViewMap.put(position,mGridView);

}

int year = position / MONTHS_IN_YEAR + startYear + ((firstMonth + (position % MONTHS_IN_YEAR)) / MONTHS_IN_YEAR);

int month = (firstMonth + (position % MONTHS_IN_YEAR)) % MONTHS_IN_YEAR;

DateBean dateBean = new DateBean(year, month + 1);

mGridView.setOnItemClickListener(this);

mGridView.setAdapter(new MyGridAdapter(dateBean));

container.addView(mGridView);

return mGridView;

}

@Override

public void destroyItem(ViewGroup container, int position, Object object) {

container.removeView((View) object);

}

@Override

public boolean isViewFromObject(View view, Object object) {

return view == object;

}

@Override

public void onItemClick(AdapterView> parent, View view, int position, long id) {

MyGridAdapter gridAdapter = (MyGridAdapter) parent.getAdapter();

int day = (int) gridAdapter.getItem(position);

if (day == -1) {

return;

}

DateBean bean = gridAdapter.getDateBean();

List list = gridAdapter.getProductDatePriceList();

if (mController!=null){

if (list!=null&&!list.isEmpty()){

mController.onDayOfMonthAndDataSelected(bean.currentYear,bean.currentMonth,day+1,list);

}else{

mController.onDayOfMonthSelected(bean.currentYear,bean.currentMonth,day+1);

}

}

}

}

通过getCount方法获取总count,确定要显示的总数。

在instantiateItem方法中根据position获取当前年月,然后为gridView设置adapter。

gridView代码如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87class MyGridAdapter extends BaseAdapter {

private DateBean mDateBean;

private int days;

private int dayOfWeeks;

private List mProductDatePriceList;

public DateBean getDateBean() {

return mDateBean;

}

public MyGridAdapter(DateBean dateBean) {

this.mDateBean = dateBean;

if (mYearMonthMap!=null){

this.mProductDatePriceList = mYearMonthMap.get(String.format("%s-%s", dateBean.currentYear, StringUtils.leftPad(dateBean.currentMonth + "", 2, "0")));

}

GregorianCalendar c = new GregorianCalendar(dateBean.currentYear, dateBean.currentMonth - 1, 0);

days = DateUtils.getDaysOfMonth(dateBean.currentYear, dateBean.currentMonth); //返回当前月的总天数。

dayOfWeeks = c.get(Calendar.DAY_OF_WEEK);

if (dayOfWeeks == 7) {

dayOfWeeks = 0;

}

}

public List getProductDatePriceList() {

return mProductDatePriceList;

}

@Override

public int getCount() {

return days + dayOfWeeks;

}

@Override

public Object getItem(int i) {

if (i < dayOfWeeks) {

return -1;

} else {

return i - dayOfWeeks;

}

}

@Override

public long getItemId(int i) {

return 0;

}

@Override

public View getView(int i, View view, ViewGroup viewGroup) {

GridViewHolder viewHolder ;

if (view == null) {

view = LayoutInflater.from(mContext).inflate(R.layout.item_day, viewGroup, false);

viewHolder = new GridViewHolder();

viewHolder.mTextView = (TextView) view.findViewById(R.id.day_tv);

viewHolder.mPriceTv = (TextView) view.findViewById(R.id.price_tv);

viewHolder.mLineView = view.findViewById(R.id.line_view);

view.setTag(viewHolder);

} else {

viewHolder = (GridViewHolder) view.getTag();

}

int item = (int) getItem(i);

if (item == -1) {

viewHolder.mTextView.setText("");

viewHolder.mPriceTv.setText("");

} else {

viewHolder.mTextView.setText(String.valueOf(item + 1));

viewHolder.mPriceTv.setText("");

if (i%7==0||i%7==6){

viewHolder.mTextView.setActivated(true);

}else{

viewHolder.mTextView.setActivated(false);

}

if (mProductDatePriceList != null) {

viewHolder.mTextView.setEnabled(false);

view.setEnabled(false);

for (Object obj : mProductDatePriceList) {//用于展示价格等额外的属性

if (mController!=null){

mController.showOtherFields(obj,view,mDateBean.currentYear,mDateBean.currentMonth,item+1);

}

}

}

}

return view;

}

}

主要是根据当前年月 获取dayOfWeeks,本月第一天为星期几,然后判断需要空出几格。

使用

简单使用

1、xml中声明view

1

2

3

4

5

6

7

1

2

3

4

5

6

7

android:id="@+id/calendarView"

android:layout_width="match_parent"

android:layout_height="wrap_content">

2、获取view并设置数据源

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16public class SimpleCalendarActivity extends AppCompatActivity {

private CommonCalendarView calendarView;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_simple_calendar);

this.calendarView = (CommonCalendarView) findViewById(R.id.calendarView);

this.calendarView.setMinDate(DateUtils.stringtoDate("1937-01-01","yyyy-MM-dd"));

this.calendarView.setMaxDate(DateUtils.stringtoDate("2100-01-22","yyyy-MM-dd"));

this.calendarView.init(null);

}

}

日历添加额外信息

1、xml中声明view

1

2

3

4

5

6

7

1

2

3

4

5

6

7

android:id="@+id/calendarView"

android:layout_width="match_parent"

android:layout_height="wrap_content">

2、获取view并且设置数据源,

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85public class MoreInfoCalendarActivity extends AppCompatActivity {

private CommonCalendarView calendarView;

private Map mYearMonthMap = new HashMap<>();

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_more_info_calendar);

List mDatePriceList = new ArrayList<>();

for (int i = 1; i <= 12; i++) {//构造12个月每天的价格数据

for (int j = 1; j <= 28; j++) {

ProductDatePrice price = new ProductDatePrice();

price.setPriceDate(String.format("-%s-%s", StringUtils.leftPad(String.valueOf(i), 2, "0"), StringUtils.leftPad(String.valueOf(j), 2, "0")));

price.setPrice(RandomUtils.nextInt(1000));

mDatePriceList.add(price);

}

}

for (ProductDatePrice productDatePrice : mDatePriceList) {//把价格数据改为同一个月的list 在一个key value里,减少渲染界面时循环判断数量

productDatePrice.getPriceDate();

String yearMonth = TextUtils.substring(productDatePrice.getPriceDate(), 0, TextUtils.lastIndexOf(productDatePrice.getPriceDate(), '-'));

List list = mYearMonthMap.get(yearMonth);

if (list == null) {

list = new ArrayList();

list.add(productDatePrice);

mYearMonthMap.put(yearMonth, list);

} else {

list.add(productDatePrice);

}

}

this.calendarView = (CommonCalendarView) findViewById(R.id.calendarView);

this.calendarView.init(new CommonCalendarView.DatePickerController() {

@Override

public int getMaxYear() {

return ;

}

@Override

public void onDayOfMonthSelected(int year, int month, int day) {

Toast.makeText(MoreInfoCalendarActivity.this, String.format("%s-%s-%s", year,StringUtils.leftPad(String.valueOf(month),2,"0"),

StringUtils.leftPad(String.valueOf(day),2,"0")), Toast.LENGTH_SHORT).show();

}

@Override

public void onDayOfMonthAndDataSelected(int year, int month, int day, List obj) {

if (obj==null){

return;

}

String priceDate = String.format("%s-%s-%s", year,

StringUtils.leftPad(month + "", 2, "0"), StringUtils.leftPad(String.valueOf(day), 2, "0"));

for (int i = 0; i < obj.size(); i++) {

ProductDatePrice datePrice = (ProductDatePrice) obj.get(i);

if (datePrice==null){

continue;

}

if (TextUtils.equals(datePrice.getPriceDate(),priceDate)){

Toast.makeText(MoreInfoCalendarActivity.this, datePrice.toString(), Toast.LENGTH_SHORT).show();

}

}

}

@Override

public void showOtherFields(Object obj, View view, int gridItemYear, int gridItemMonth, int gridItemDay) {

//当你设置了数据源之后,界面渲染会循环调用showOtherFields方法,在该方法中实现同一日期设置界面显示效果。

ProductDatePrice productDatePrice = (ProductDatePrice) obj;

if (TextUtils.equals(productDatePrice.getPriceDate(), String.format("%s-%s-%s", gridItemYear,

StringUtils.leftPad(gridItemMonth + "", 2, "0"), StringUtils.leftPad(String.valueOf(gridItemDay), 2, "0")))) {

CommonCalendarView.GridViewHolder viewHolder = (CommonCalendarView.GridViewHolder) view.getTag();

viewHolder.mPriceTv.setText(String.format("¥ %s", productDatePrice.getPrice()));

view.setEnabled(true);

viewHolder.mTextView.setEnabled(true);

}

}

@Override

public Map getDataSource() {

return mYearMonthMap;

}

});

}

}

结语

本偏的自定义价格日历控件还有很多不完善的地方,在这里分享出来只是抛砖引玉,希望对大家有所帮助,欢迎关注我的博客!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。