标签: 控件

iOS 滚动数字控件:DPScrollNumberLabel 实现

写在前面
*次写博客,有点小激动,同时也害怕写的很烂,所以希望大家能够包容,如果大家觉得看不下去我的博客,可以直接翻到*后有源码和demo的github地址。开发ios也有大半年了,所以想要尝试一下写点博客,好了废话不多说了下面开始正题了。

正文
简介
由于公司前段时间项目里要用到一个可以滚动的数字标签,所以就写了这样一个控件,现在有时间了,就写篇博客记录一下实现这个控件的过程。

上一张gif动画

这个控件的逻辑是当个位数从0~9~0时十位数向上滚动1,当十位完成一个0~9~0循环时,百位向上滚动1依次类推

实现思路
先说一下我实现这个控件的思路,其实比较简单,数字的每一列都是一个很长的UILabel,然后由上至下是数字0~9,当数字改变时,让这个label上下移动,产生滚动的动画,只需要计算循环的次数,滚动的方向,滚动的时间就可以了。

Talk is cheap,show you The code!
首先看一下头文件里的内容:
//
// DPScrollNumberLabel.h
// DPScrollNumberLabelDemo
//
// Created by Dai Pei on 16/5/23.
// Copyright © 2016年 Dai Pei. All rights reserved.
//

#import <UIKit/UIKit.h>

@interface DPScrollNumberLabel : UIView

@property (nonatomic, strong)NSNumber *displayedNumber;

– (instancetype)initWithNumber:(NSNumber *)originNumber fontSize:(CGFloat)size;
– (instancetype)initWithNumber:(NSNumber *)originNumber fontSize:(CGFloat)size textColor:(UIColor *)color;
– (instancetype)initWithNumber:(NSNumber *)originNumber font:(UIFont *)font;
– (instancetype)initWithNumber:(NSNumber *)originNumber font:(UIFont *)font textColor:(UIColor *)color;
– (instancetype)initWithNumber:(NSNumber *)originNumber fontSize:(CGFloat)size rowNumber:(NSUInteger)rowNumber;
– (instancetype)initWithNumber:(NSNumber *)originNumber fontSize:(CGFloat)size textColor:(UIColor *)color rowNumber:(NSUInteger)rowNumber;
– (instancetype)initWithNumber:(NSNumber *)originNumber font:(UIFont *)font textColor:(UIColor *)color rowNumber:(NSUInteger)rowNumber;//rowNumber should less than or equal 8

– (void)changeToNumber:(NSNumber *)number animated:(BOOL)animated;
– (void)changeToNumber:(NSNumber *)number interval:(CGFloat)interval animated:(BOOL)animated;
@end
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
可以看到头文件里有7个初始化方法,分为两大类:规定列数和不规定列数。当规定列数时,则控件的列数固定,当传入的数字大于列数限制时函数直接返回,当不规定列数时,以初始化传入的数字的列数为初始列数,当后面传入的数字大于初始列数时,会自动在左边补加列(*大列数不能超过8列)
其中*重要的一个参数是字体的大小,我需要这个参数去计算此控件的大小。
另外两个方法当需要显示的数字改变时调用,animated传入YES时会有动画,传入NO时直接改变不播放动画。

下面只贴上其中一个init方法:
– (instancetype)initWithNumber:(NSNumber *)originNumber fontSize:(CGFloat)size textColor:(UIColor *)color rowNumber:(NSUInteger)rowNumber {
self = [super init];
if (self) {
self.displayedNumber = originNumber;
self.font = [UIFont systemFontOfSize:size];
self.textColor = color;
self.isAnimation = NO;
self.finishedAnimationCount = 0;
self.rowNumber = (rowNumber > 0 && rowNumber <= 8) ? rowNumber : 0;
self.maxRowNumber = (self.rowNumber == 0) ? 8 : rowNumber;
[self commonInit];
}
return self;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
初始化后进入commonInit方法:
– (void)commonInit {
[self initCell];
[self initParent];
}
1
2
3
4
然后先初始化cell,再初始化parent:
– (void)initCell {
int originNumber = self.displayedNumber.intValue;
//如果没有规定列数 就自己计算 方法具体实现会在后面贴出
if (self.rowNumber == 0) {
self.rowNumber = [self calculateRowNumber:originNumber];
}
//用于保存所有的cell
self.cellArray = [[NSMutableArray alloc] init];
NSString *text = @”0\n1\n2\n3\n4\n5\n6\n7\n8\n9\n0″;
//这个方法很赞 可以直接根据内容来计算一个view的大小
CGRect rect = [text boundingRectWithSize:CGSizeZero
options:NSStringDrawingUsesLineFragmentOrigin
attributes:@{NSFontAttributeName:self.font} context:nil];
//然后保存宽度和高度值,后面很多地方都会用到
self.cellWidth = rect.size.width;
self.cellHeight = rect.size.height;
//拿到每个位数上显示的数字并保存在一个数组中
NSArray *displayNumberArray = [self getCellDisplayNumberWithNumber:self.displayedNumber.integerValue];
//初始化每个cell 并且保存在数组中
for (NSInteger i = 0; i < self.rowNumber; i++) {
UILabel *scrollCell = [self makeScrollCell];
scrollCell.frame = CGRectMake((self.rowNumber – 1 – i) * self.cellWidth, 0, self.cellWidth, self.cellHeight);
scrollCell.text = text;
NSNumber *displayNum = [displayNumberArray objectAtIndex:i];
//此方法调整cell的位置,使其显示相应的数字 方法具体实现会在后面贴出
[self setScrollCell:scrollCell toNumber:displayNum.integerValue];
[self.cellArray addObject:scrollCell];
}
}
#pragma mark – Getters
– (UILabel *)makeScrollCell {
UILabel *cell = [[UILabel alloc] init];
cell.font = self.font;
cell.numberOfLines = 11;
cell.textColor = self.textColor;
return cell;
}
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
然后是实现parent:

– (void)initParent{
self.bounds = CGRectMake(0, 0, self.rowNumber * self.cellWidth, self.cellHeight / 11);
self.backgroundColor = [UIColor clearColor];
self.layer.masksToBounds = YES;
//把cell布局到parent中
[self layoutCell:self.rowNumber withAnimation:YES];
}
1
2
3
4
5
6
7
– (void)layoutCell:(NSUInteger)rowNumber withAnimation:(BOOL)animated{
//先将子view全部移除 此处移除是有原因的
for (UIView *subView in self.subviews) {
[subView removeFromSuperview];
}
//再添加进去
for (UILabel *cell in self.cellArray) {
[self addSubview:cell];
}
//此处用动画重新排列所有的cell
__weak typeof(self) weakSelf = self;
[UIView animateWithDuration:0.2 * (rowNumber – self.rowNumber) animations:^{
for (int i = 0; i < rowNumber; i++) {
UILabel *cell = [weakSelf.cellArray objectAtIndex:i];
cell.frame = CGRectMake((rowNumber – 1 – i) * weakSelf.cellWidth,
cell.frame.origin.y,
weakSelf.cellWidth,
weakSelf.cellHeight);
}
self.frame = CGRectMake(self.frame.origin.x,
self.frame.origin.y,
rowNumber * self.cellWidth,
self.cellHeight/11);
} completion:nil];
}
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
至此,初始化的工作全部完成

下面让我们关注头文件里另外的两个公有方法:
– (void)changeToNumber:(NSNumber *)number animated:(BOOL)animated {

[self changeToNumber:number interval:0 animated:animated];
}

– (void)changeToNumber:(NSNumber *)number interval:(CGFloat)interval animated:(BOOL)animated {
//因为没有做负数部分,所以当传入的数字小于0 直接返回
if (number.integerValue < 0) {
return ;
}
//当大于*大行数,直接返回
if ([self calculateRowNumber:number.integerValue] > self.maxRowNumber) {
return ;
}
//如果传入数字和本身显示相同,直接返回
if (number.integerValue == self.displayedNumber.integerValue) {
return ;
}
//当传入数字时,当前动画还没有播放完成,加入数组,等待动画播放完成
if (self.isAnimation) {
if (!self.taskArray) {
self.taskArray = [NSMutableArray array];
}
[self.taskArray addObject:@{keyTaskDisplayNumber:number, keyTaskChangeNumber:@(number.integerValue – self.displayedNumber.integerValue),keyTaskInterval:@(interval)}];
}else {
if (animated) {
//animated 为YES时 进入此方法
[self playAnimationWithChange:number.integerValue – self.displayedNumber.integerValue displayNumber:number interval:interval];
self.isAnimation = YES;
}else {
//animated 为NO时 直接改变
//这个方法在前面说过,具体实现会在后面贴出
NSArray<NSNumber *> *displayNumbers = [self getCellDisplayNumberWithNumber:number.integerValue];
for (int i = 0; i < displayNumbers.count; i++) {
[self setScrollCell:self.cellArray[i] toNumber:displayNumbers[i].integerValue];
}
}
}
self.displayedNumber = number;
}
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
下面就要进入动画部分了
static const CGFloat bufferModulus = 0.7f;

– (void)playAnimationWithChange:(NSInteger)changeNumber displayNumber:(NSNumber *)displayNumber interval:(CGFloat)interval{
//改名后的列数
NSInteger nextRowNumber = [self calculateRowNumber:displayNumber.intValue];
//只有当列数增加时才重新布局
if (nextRowNumber > self.rowNumber) {
[self reInitCell:nextRowNumber];
[self layoutCell:nextRowNumber withAnimation:YES];
self.rowNumber = nextRowNumber;
}
//储存每一位循环次数的数组
NSArray *repeatCountArray = [self getRepeatTimesWithChangeNumber:changeNumber displayNumber:displayNumber.integerValue];
//储存每一位将显示的数值
NSArray *willDisplayNums = [self getCellDisplayNumberWithNumber:displayNumber.integerValue];

//如果没有设置动画间隔,则根据改变的大小来进行计算
if (interval == 0) {
interval = [self getIntervalWithOriginalNumber:displayNumber.integerValue – changeNumber displayNumber:displayNumber.integerValue];
}
//获得滚动的方向
ScrollAnimationDirection direction = (changeNumber > 0)? ScrollAnimationDirectionUp : ScrollAnimationDirectionDown;

CGFloat delay = 0.0f;

if (repeatCountArray.count != 0) {
for (NSInteger i = 0; i < repeatCountArray.count; i++) {
NSNumber *repeat = [repeatCountArray objectAtIndex:i];
NSInteger repeatCount = repeat.integerValue;
NSNumber *willDisplayNum = [willDisplayNums objectAtIndex:i];
UILabel *cell = [self.cellArray objectAtIndex:i];
CGFloat startDuration = 0;
//当不是一个完整0~9~0循环时,只进行一个Single动画(我将这里的动画分为两类:single和multi)
if (repeatCount == 0) {
[self makeSingleAnimationWithCell:cell duration:interval delay:delay animationCount:repeatCountArray.count displayNumber:willDisplayNum.integerValue];
}else {
//当>=一个循环时,进行multi动画
if (direction == ScrollAnimationDirectionUp) {
//此处计算三个部分的动画时间
startDuration = interval * (10 – [self getDisplayNumberOfCell:cell]) / ceilf(fabs(changeNumber / pow(10, i)));
CGFloat cycleDuration = interval * 10 / fabs(changeNumber / pow(10, i));
if (repeatCount == 1) {
cycleDuration = 0;
}
CGFloat endDuration = bufferModulus * pow(willDisplayNum.integerValue, 0.3) / (i + 1);
NSDictionary *attribute = @{keyStartDuration: @(startDuration),
keyStartDelay: @(delay),
keyCycleDuration: @(cycleDuration),
keyEndDuration: @(endDuration),
keyRepeatCount: @(repeatCount – 1),
keyDisplayNumber: willDisplayNum};
[self makeMultiAnimationWithCell:cell direction:direction animationCount:repeatCountArray.count attribute:attribute];
}else if (direction == ScrollAnimationDirectionDown) {
startDuration = interval * ([self getDisplayNumberOfCell:cell] – 0) / ceilf(fabs(changeNumber / pow(10, i)));
CGFloat cycleDuration = interval * 10 / fabs(changeNumber / pow(10, i));
//此处可能有些疑问,因为这个repeatCount不是真正循环的次数,是cycle的次数加end部分的1,所以如果repeat为1 真正循环次数是0
if (repeatCount == 1) {
cycleDuration = 0;
}
CGFloat endDuration = bufferModulus * pow(10 – willDisplayNum.integerValue, 0.3) / (i + 1);
NSDictionary *attribute = @{keyStartDuration: @(startDuration),
keyStartDelay: @(delay),
keyCycleDuration: @(cycleDuration),
keyEndDuration: @(endDuration),
keyRepeatCount: @(repeatCount – 1),
keyDisplayNumber: willDisplayNum};
[self makeMultiAnimationWithCell:cell direction:direction animationCount:repeatCountArray.count attribute:attribute];
}
}
delay = delay + startDuration;
}
}
}
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
动画分为single和multi两种,multi动画里包括3个部分start,cycle,end;start部分是当前数值~9的动画,cycle部分是0~9的数次循环,end部分为0~*终数值(此处以数字增加举例,数字减少时相反)

下面贴出single和multi两种动画的代码:
– (void)makeSingleAnimationWithCell:(UILabel *)cell duration:(CGFloat)duration delay:(CGFloat)delay animationCount:(NSInteger)count displayNumber:(NSInteger)displayNumber{

[UIView animateWithDuration:duration delay:delay options:UIViewAnimationOptionCurveEaseOut animations:^{
[self setScrollCell:cell toNumber:displayNumber];
} completion:^(BOOL finished) {
//当动画结束,检查是否有待执行的动画
[self checkTaskArrayWithAnimationCount:count];
NSLog(@”single animation finish!”);
}];
}
– (void)makeMultiAnimationWithCell:(UILabel *)cell
direction:(ScrollAnimationDirection)direction
animationCount:(NSInteger)count
attribute:(NSDictionary *)attribute{
NSNumber *startDuration = [attribute objectForKey:keyStartDuration];
NSNumber *cycleDuration = [attribute objectForKey:keyCycleDuration];
NSNumber *endDuration = [attribute objectForKey:keyEndDuration];
NSNumber *repeatCount = [attribute objectForKey:keyRepeatCount];
NSNumber *willDisplayNum = [attribute objectForKey:keyDisplayNumber];
NSNumber *startDelay = [attribute objectForKey:keyStartDelay];

[UIView animateWithDuration:startDuration.floatValue delay:startDelay.floatValue options:UIViewAnimationOptionCurveEaseIn animations:^{
//这是开始部分的动画
[self setScrollCell:cell toNumber:(direction == ScrollAnimationDirectionUp)?10 : 0];
} completion:^(BOOL finished) {
NSLog(@”start animation finish!”);
//开始动画结束后将cell归位到循环开始的地方
[self setScrollCell:cell toNumber:(direction == ScrollAnimationDirectionUp)?0 : 10];

if (cycleDuration.floatValue == 0) {
//当循环次数为0,直接执行结束部分的动画
[UIView animateWithDuration:endDuration.floatValue delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
[self setScrollCell:cell toNumber:willDisplayNum.integerValue];
} completion:^(BOOL finished) {
[self checkTaskArrayWithAnimationCount:count];
NSLog(@”end animation finish!”);
}];
}else {
//否则进入循环动画
[UIView animateWithDuration:cycleDuration.floatValue delay:0 options:UIViewAnimationOptionCurveLinear | UIViewAnimationOptionRepeat animations:^{
[UIView setAnimationRepeatCount:repeatCount.integerValue];
switch (direction) {
case ScrollAnimationDirectionUp:
[self setScrollCell:cell toNumber:10];
break;
case ScrollAnimationDirectionDown:
[self setScrollCell:cell toNumber:0];
break;
default:
break;
}
} completion:^(BOOL finished) {
NSLog(@”cycle animation finish!”);
[self setScrollCell:cell toNumber:(direction == ScrollAnimationDirectionUp)?0 : 10];
//这是循环后的结束动画
[UIView animateWithDuration:endDuration.floatValue delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
[self setScrollCell:cell toNumber:willDisplayNum.integerValue];
} completion:^(BOOL finished) {
[self checkTaskArrayWithAnimationCount:count];
NSLog(@”end animation finish!”);
}];
}];
}
}];
}
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
核心动画部分代码都已经贴出来了,下面看下一些privite方法

首先是每个动画结束的checkTaskArrayWithAnimationCount:方法
//这里传入的cout是一次变化总共的动画次数
– (void)checkTaskArrayWithAnimationCount:(NSInteger)count {
//每个动画结束,计数加一,当等于count时,说明所有动画都已经结束了
self.finishedAnimationCount++;
if (self.finishedAnimationCount == count) {
self.finishedAnimationCount = 0;
if (self.taskArray.count != 0) {
NSDictionary *task = [self.taskArray objectAtIndex:0];
[self.taskArray removeObject:task];
NSNumber *displayNumber = [task objectForKey:keyTaskDisplayNumber];
NSNumber *changeNumber = [task objectForKey:keyTaskChangeNumber];
NSNumber *interval = [task objectForKey:keyTaskInterval];
//如果taskArray里有task,则进行下一次动画
[self playAnimationWithChange:changeNumber.integerValue displayNumber:displayNumber interval:interval.floatValue];
}else {
self.isAnimation = NO;
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
计算列数的方法:calculateRowNumber:
这个方法很简单,就不做解释了

– (NSInteger)calculateRowNumber:(NSInteger)number {
NSInteger rowNumber = 1;
while ((number = number / 10) != 0) {
rowNumber++;
}
return rowNumber;
}
1
2
3
4
5
6
7
使指定cell显示相应数值的方法:setScrollCell: toNumber:
– (void)setScrollCell:(UILabel *)cell toNumber:(NSInteger)number {
CGFloat originX = cell.frame.origin.x;
CGFloat floatNumber = number;
CGFloat y = – ((CGFloat)floatNumber / 11) * self.cellHeight;
cell.frame = CGRectMake(originX, y, self.cellWidth, self.cellHeight);
}
1
2
3
4
5
6
计算repeatCount的方法:getRepeatTimesWithChangeNumber: displayNumber:
这个方法我想用几个小例子来解释,等看完这个例子,再去看代码就不会觉得那么难懂了:比如当前展示数为521,要让它改变到530,注意个位数要循环多少次呢,其实它只有开始部分和结束部分,并没有循环部分,我代码的操作是将个位置0,520和530,530-520=10,10/10^1=1所以得到的循环次数是1,而我前面说过这个1不是真正的循环次数,而是循环次数加上end部分的1,所以当repeatCount=1时,只会有开始动画和结束动画。再举一个例子:521和542,先置0,520和540,520-540=20,20/10^1=2,repeatCount=2,而真正循环次数为1,我们看,当521经过开始动画变位530,随后经过一个循环变为540,再经过结束动画到达542,那么真正循环确实是1次,说明这种算法没有问题。当然这只举了个位为例,其它位以此类推都是相同的。

– (NSArray<NSNumber *> *)getRepeatTimesWithChangeNumber:(NSInteger)change displayNumber:(NSInteger)number{
NSMutableArray *repeatTimesArray = [[NSMutableArray alloc] init];
NSInteger originNumber = number – change;
if (change > 0) {
do {
number = (number / 10) * 10;
originNumber = (originNumber / 10) * 10;
NSNumber *repeat = @((number – originNumber) / 10);
[repeatTimesArray addObject:repeat];
number = number / 10;
originNumber = originNumber / 10;
} while ((number – originNumber) != 0);
}else {
do {
number = (number / 10) * 10;
originNumber = (originNumber / 10) * 10;
NSNumber *repeat = @((originNumber – number) / 10);
[repeatTimesArray addObject:repeat];
number = number / 10;
originNumber = originNumber / 10;
} while ((originNumber – number) != 0);
}
return repeatTimesArray;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
将一个数字准换为各位上应当展示的数值的方法:getCellDisplayNumberWithNumber:
举个例子就是这个数字是:521,则返回一个数组:[@1,@2,@5]

– (NSArray<NSNumber *> *)getCellDisplayNumberWithNumber:(NSInteger)displayNumber {
NSMutableArray *displayCellNumbers = [[NSMutableArray alloc] init];
NSInteger tmpNumber;
for (NSInteger i = 0; i < self.rowNumber; i++) {
tmpNumber = displayNumber % 10;
NSNumber *number = @(tmpNumber);
[displayCellNumbers addObject:number];
displayNumber = displayNumber / 10;
}
return displayCellNumbers;
}
1
2
3
4
5
6
7
8
9
10
11
获得指定cell展示的数值的方法:getDisplayNumberOfCell:
– (NSInteger)getDisplayNumberOfCell:(UILabel *)cell {
CGFloat y = cell.frame.origin.y;
CGFloat tmpNumber = (- (y * 11 / self.cellHeight));
NSInteger displayNumber = (NSInteger)roundf(tmpNumber);
return displayNumber;
}
1
2
3
4
5
6
计算动画总时间的方法:getIntervalWithOriginalNumber: displayNumber:
这个时间是根据*高位改变的位数来计算的,位数越高,每改变一次时间就越长。

static const CGFloat normalModulus = 0.3f;

– (CGFloat)getIntervalWithOriginalNumber:(NSInteger)number displayNumber:(NSInteger)displayNumber {

NSArray *repeatTimesArray = [self getRepeatTimesWithChangeNumber:displayNumber – number displayNumber:displayNumber];
NSUInteger count = repeatTimesArray.count;
NSInteger tmp1 = displayNumber / (NSInteger)pow(10, count – 1);
NSInteger tmp2 = number / (NSInteger)pow(10, count – 1);

NSLog(@”tmp1:%ld tmp2:%ld”, (long)tmp1, (long)tmp2);
NSInteger maxChangeNum = labs(tmp1 % 10 – tmp2 % 10);

return normalModulus * count * maxChangeNum;

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
代码部分到此结束
————————————————
版权声明:本文为CSDN博主「太肥小次郎」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/dp948080952/article/details/51871485

【android】NavigationView控件的使用

这是Google在Android5.0之后推出的一个控件,兼容到Android2.1,代替之前自己做抽屉菜单,简单方便。NavigationView整体分为上下两个部分,上部分叫做HeaderLayout,下面的点击项都是menu。

%title插图%num

NavigationView的使用方法
1、写布局文件
整体布局
<android.support.v4.widget.DrawerLayout xmlns:android=”http://schemas.android.com/apk/res/android”
xmls:app=”http://schemas.android.com/apk/res-auto”
xmls:tools=”http://schemas.android.com/tools”
android:id=”@_id/item_layout”
android:layout_width=”match_parent”
android:layout_height=”match_parent”
android:fitsSystemWindows=”true”
tools:openDrawer=”start”>

<include
layout=”@layout/weather_layout”
android:layout_width=”match_parent”
android:layout_height=”match_parent” />

<android.support.design.widget.NavigationView
android:id=”@+id/nav_view”
android:layout_width=”wrap_content”
android:layout_height=”match_parent”
android:layout_gravity=”start”
android:fitsSystemWindows=”true”
app:headerLayout=”@layout/nav_header_main”
app:menu=”@menu/activity_main_drawer”/>

</android.support.v4.widget.DrawerLayout>

代码解释:*外层是个DrawerLayout,

headerLayout
看一下headerLayout(app:headerLayout=”@layout/nav_header_main”)的代码:

<?xml version=”1.0″ encoding=”utf-8″?>
<LinearLayout xmlns:android=”http://schemas.android.com/apk/res/android”
android:layout_width=”match_parent”
android:layout_height=”160dp”
android:background=”#81c0c0″
android:gravity=”bottom”
android:paddingBottom=”@dimen/activity_vertical_margin”
android:paddingLeft=”@dimen/activity_horizontal_margin”
android:paddingRight=”@dimen/activity_horizontal_margin”
android:paddingTop=”@dimen/activity_vertical_margin”
android:orientation=”vertical”>

<ImageView
android:id=”@+id/imageView”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:paddingTop=”16dp”
android:src=”@mipmap/cloud” />

<TextView
android:layout_width=”match_parent”
android:layout_height=”wrap_content”
android:paddingTop=”16dp”
android:text=”Weather”
android:textAppearance=”@style/TextAppearance.AppCompat.Body1″/>

<TextView
android:id=”@+id/textView”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:text=”Designed by Wangmj” />

</LinearLayout>

完成之后是下面这个样子

%title插图%num
menu
再看一下menu(app:menu=”@menu/activity_main_drawer”) 的代码:

<?xml version=”1.0″ encoding=”utf-8″?>
<menu xmlns:android=”http://schemas.android.com/apk/res/android”>

<group android:checkableBehavior=”single”>
<item
android:id=”@+id/select_city”
android:icon=”@mipmap/checklist_64px”
android:title=”选择城市” />
</group>

<item android:title=”Communicate”>
<menu>
<item
android:id=”@+id/share”
android:icon=”@mipmap/share_48px”
android:title=”分享” />
</menu>
</item>

</menu>

这里可以分组,虽然我写的组里面只有一个item,现在还没有那么多功能,慢慢加啦;组与组之间会有分割线,这里只有一个组,所以没有。

%title插图%num
content
接下来再来看一下content的布局文件:

<LinearLayout xmlns:android=”http://schemas.android.com/apk/res/android”
android:layout_width=”match_parent”
android:layout_height=”match_parent”
xmlns:app=”http://schemas.android.com/apk/res-auto”
android:orientation=”vertical”>

<RelativeLayout
android:id=”@+id/top”
android:layout_width=”match_parent”
android:layout_height=”50dp”
android:background=”#408080″>

<android.support.v7.widget.Toolbar
android:id=”@+id/menu_button”
android:layout_width=”30dp”
android:layout_height=”30dp”
android:layout_centerVertical=”true”
android:layout_marginLeft=”10dp”/>
<!–android:background=”@mipmap/home”–>

<TextView
android:id=”@+id/city_name”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:layout_centerInParent=”true”
android:textColor=”#fff”
android:textSize=”24dp”
android:text=”city_name”/>
<Button
android:id=”@+id/refresh_weather”
android:layout_width=”30dp”
android:layout_height=”30dp”
android:layout_alignParentRight=”true”
android:layout_centerVertical=”true”
android:layout_marginRight=”10dp”
android:background=”@mipmap/refresh”/>
</RelativeLayout>

<RelativeLayout
android:layout_width=”match_parent”
android:layout_height=”0dp”
android:layout_weight=”1″
android:background=”#81C0C0″>

<TextView
android:id=”@+id/publish_text”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:layout_alignParentRight=”true”
android:layout_marginRight=”10dp”
android:layout_marginTop=”10dp”
android:textColor=”#FFF”
android:textSize=”18sp”/>

<LinearLayout
android:id=”@+id/weather_info_layout”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:layout_centerInParent=”true”
android:orientation=”vertical”>

<TextView
android:id=”@+id/current_data”
android:layout_width=”wrap_content”
android:layout_height=”40dp”
android:gravity=”center”
android:textColor=”#fff”
android:textSize=”18sp”/>

<TextView
android:id=”@+id/weather_desp”
android:layout_width=”wrap_content”
android:layout_height=”60sp”
android:layout_gravity=”center_horizontal”
android:gravity=”center”
android:textColor=”#fff”
android:textSize=”40sp”/>

<LinearLayout
android:layout_width=”wrap_content”
android:layout_height=”60dp”
android:layout_gravity=”center_horizontal”
android:orientation=”horizontal”>

<TextView
android:id=”@+id/temp1″
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:layout_weight=”3″
android:layout_gravity=”center_vertical”
android:textColor=”#fff”
android:textSize=”20sp”/>

<TextView
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:layout_gravity=”center_vertical”
android:layout_marginLeft=”10dp”
android:layout_marginRight=”10dp”
android:layout_weight=”1″
android:text=”~”
android:textColor=”#fff”
android:textSize=”20sp”/>

<TextView
android:id=”@+id/temp2″
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:layout_weight=”3″
android:layout_gravity=”center_vertical”
android:textColor=”#fff”
android:textSize=”20sp”/>
</LinearLayout>
</LinearLayout>
</RelativeLayout>
</LinearLayout>

代码解释:Toolbar底下的内容都不用管,主要是Toolbar和NavigationView有关系,所以只用看Toobar。

2.点击事件
public class WeatherActivity extends Activity implements NavigationView.OnNavigationItemSelectedListener{

/**
* 菜单按钮
*/
private Toolbar menuButton;
/**
* 菜单布局
*/
private DrawerLayout itemLayout;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.item_layout);
itemLayout=(DrawerLayout)findViewById(R.id.item_layout);
menuButton=(Toolbar) findViewById(R.id.menu_button);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, itemLayout, menuButton,R.string.navigation_drawer_open, R.string.navigation_drawer_close);
itemLayout.setDrawerListener(toggle);
toggle.syncState();
NavigationView navigationView=(NavigationView)findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);

}

@Override
public boolean onNavigationItemSelected(MenuItem item) {
int id=item.getItemId();
switch (id){
case R.id.select_city:
Intent intent=new Intent(this,ChooseAreaActivity.class);
intent.putExtra(“from_weather_activity”,true);
startActivity(intent);
finish();
break;
case R.id.share:
Toast.makeText(WeatherActivity.this, “正在开发中…”, Toast.LENGTH_SHORT).show();
break;
//可以更多,只要在menu的布局文件里声明。
}
return false;
}
}

结束。

友情链接: SITEMAP | 旋风加速器官网 | 旋风软件中心 | textarea | 黑洞加速器 | jiaohess | 老王加速器 | 烧饼哥加速器 | 小蓝鸟 | tiktok加速器 | 旋风加速度器 | 旋风加速 | quickq加速器 | 飞驰加速器 | 飞鸟加速器 | 狗急加速器 | hammer加速器 | trafficace | 原子加速器 | 葫芦加速器 | 麦旋风 | 油管加速器 | anycastly | INS加速器 | INS加速器免费版 | 免费vqn加速外网 | 旋风加速器 | 快橙加速器 | 啊哈加速器 | 迷雾通 | 优途加速器 | 海外播 | 坚果加速器 | 海外vqn加速 | 蘑菇加速器 | 毛豆加速器 | 接码平台 | 接码S | 西柚加速器 | 快柠檬加速器 | 黑洞加速 | falemon | 快橙加速器 | anycast加速器 | ibaidu | moneytreeblog | 坚果加速器 | 派币加速器 | 飞鸟加速器 | 毛豆APP | PIKPAK | 安卓vqn免费 | 一元机场加速器 | 一元机场 | 老王加速器 | 黑洞加速器 | 白石山 | 小牛加速器 | 黑洞加速 | 迷雾通官网 | 迷雾通 | 迷雾通加速器 | 十大免费加速神器 | 猎豹加速器 | 蚂蚁加速器 | 坚果加速器 | 黑洞加速 | 银河加速器 | 猎豹加速器 | 海鸥加速器 | 芒果加速器 | 小牛加速器 | 极光加速器 | 黑洞加速 | movabletype中文网 | 猎豹加速器官网 | 烧饼哥加速器官网 | 旋风加速器度器 | 哔咔漫画 | PicACG | 雷霆加速