模仿网易新闻客户端(RSS版)(一)

来源:互联网 发布:apache认证 编辑:程序博客网 时间:2024/06/06 12:23
2012033100313348.png     2012033100314616.png    2012033100315576.png 

2012033100320229.png     2012033100321095.png 

三、底部类似TabHost组件切换效果的实现

为了便于大家亲自动手实践,这里的讲解顺序就按照开发的顺序来讲,所以先做这个底部的“TabHost”,然后再具体来实现里面的五个页面布局。

类似于图3到图5三张图片所示,当点击“新闻”或者“话题”或者“投票”的时候,有个稍微透明的红色背景的ImageView做相应的移动。这其实就是给ImageView设置了一个位移动画,当点击事件触发的时候,首先切换点击后的图片(有点类似于按下效果的图片),然后开始移动铺在上面的红色图片,让用户感觉到有移动的过程,增强用户体验。

关于这个位移动画,需要用到TranslateAnimation类,移动的核心代码也就几行,因为这个移动功能不但在底部控件上使用,而且在顶部也使用了,所以,为了以后使用方便,我们把它单独定义在一个类里面MoveBg.java
?
代码片段,双击复制
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
View Code
 
packagecom.and.netease.utils;
 
importandroid.view.View;
importandroid.view.animation.TranslateAnimation;
 
publicclass MoveBg {
   /**
     * 移动方法
     *
     * @param v
     *            需要移动的View
     * @param startX
     *            起始x坐标
     * @param toX
     *            终止x坐标
     * @param startY
     *            起始y坐标
     * @param toY
     *            终止y坐标
     */
   publicstatic void moveFrontBg(View v, intstartX, inttoX, intstartY, inttoY) {
        TranslateAnimation anim = newTranslateAnimation(startX, toX, startY, toY);
        anim.setDuration(200);
        anim.setFillAfter(true);
        v.startAnimation(anim);
   }
}


里面的各个参数有相应的说明。

然后就来开发这个带有TabHost功能的组件。根据文档http://developer.android.com/resources/tutorials/views/hello-tabwidget.html说明,在xml中定义TabHost的时候,必须使用TabWidget和FrameLayou两个组件,而且它们的id也应该是android:id="@android:id/tabs"和android:id="@android:id/tabcontent",由于系统提供的TabHost界面不怎么好看,所以这里想到自己来定义它,但是这两个组件是不可以不写的,这里,把TabWidget界面隐藏掉了,取而代之的是RadioGroup组件来实现底部类似于TabHost的控件。具体布局代码如main.xml
?
代码片段,双击复制
01
02
03
04
05
06
07
08
09
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
View Code
 
<?xml version="1.0"encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
   android:layout_width="fill_parent"
   android:layout_height="fill_parent"
   android:orientation="vertical">
 
   <TabHost
        android:id="@android:id/tabhost"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent">
 
        <LinearLayout
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:orientation="vertical">
 
            <FrameLayout
                android:id="@android:id/tabcontent"
                android:layout_width="fill_parent"
                android:layout_height="0.0dip"
                android:layout_weight="1.0">
            </FrameLayout>
 
            <TabWidget
                android:id="@android:id/tabs"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                android:visibility="gone"/>
 
            <RelativeLayout
                android:id="@+id/layout_bottom"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content">
 
                <RadioGroup
                    android:id="@+id/radiogroup"
                    android:layout_width="fill_parent"
                    android:layout_height="wrap_content"
                    android:layout_gravity="bottom"
                    android:background="@drawable/bottombg"
                    android:gravity="center_vertical"
                    android:orientation="horizontal">
 
                    <RadioButton
                        android:id="@+id/radio_news"
                        android:layout_width="wrap_content"
                        android:background="@drawable/tab_selector_news"
                        android:button="@null"
                        android:checked="true"/>
 
                    <RadioButton
                        android:id="@+id/radio_topic"
                        android:layout_width="wrap_content"
                        android:background="@drawable/tab_selector_topic"
                        android:button="@null"/>
 
                    <RadioButton
                        android:id="@+id/radio_pic"
                        android:layout_width="wrap_content"
                        android:background="@drawable/tab_selector_pic"
                        android:button="@null"/>
 
                    <RadioButton
                        android:id="@+id/radio_follow"
                        android:layout_width="wrap_content"
                        android:background="@drawable/tab_selector_follow"
                        android:button="@null"/>
 
                    <RadioButton
                        android:id="@+id/radio_vote"
                        android:layout_width="wrap_content"
                        android:background="@drawable/tab_selector_vote"
                        android:button="@null"/>
                </RadioGroup>
            </RelativeLayout>
        </LinearLayout>
   </TabHost>
 
</LinearLayout>


注意里面的RadioButton组件,当初测试的时候没有设置android:button="@null",只设置了background="@drawable/..."属性(这是一个selector属性,可以在xml文件中定义一些控件的按下效果,或者获取焦点等不同状态下的资源),出现点击不切换图片的问题。

对应的selector文件对应如下tab_selector_news.xml
?
代码片段,双击复制
01
02
03
04
05
06
07
08
09
View Code
 
<?xml version="1.0"encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
 
   <item android:drawable="@drawable/current_news_tab"android:state_checked="true"/>
   <item android:drawable="@drawable/back_news_tab"android:state_checked="false"/>
 
</selector>


其它几个,只是替换不同的图片资源罢了,不再一一列出。这些资源文件放在res目录下的drawable文件夹下(如果没有,则新建)

有了布局文件,还需要在Activity中设置一下,为每个TabHost添加具体的Tab页面,如下
?
代码片段,双击复制
01
02
03
04
05
06
tabHost = getTabHost();
        tabHost.addTab(tabHost.newTabSpec("news").setIndicator("News").setContent(newIntent(this, TabNewsActivity.class)));
        tabHost.addTab(tabHost.newTabSpec("topic").setIndicator("Topic").setContent(newIntent(this, TabTopicActivity.class)));
        tabHost.addTab(tabHost.newTabSpec("picture").setIndicator("Picture").setContent(newIntent(this, TabPicActivity.class)));
        tabHost.addTab(tabHost.newTabSpec("follow").setIndicator("Follow").setContent(newIntent(this, TabFollowActivity.class)));
        tabHost.addTab(tabHost.newTabSpec("vote").setIndicator("Vote").setContent(newIntent(this, TabVoteActivity.class)));


当然,相应的目标Activity自然暂且随意创建

然后为RadioGroup设置选择改变事件监听器,当选择改变,改变TabHost中当前显示的Activity页面

?
代码片段,双击复制
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
privateOnCheckedChangeListener checkedChangeListener = newOnCheckedChangeListener() {
 
        @Override
        publicvoid onCheckedChanged(RadioGroup group, intcheckedId) {
            switch(checkedId) {
            caseR.id.radio_news:
                tabHost.setCurrentTabByTag("news");
                break;
            caseR.id.radio_topic:
                tabHost.setCurrentTabByTag("topic");
                break;
            caseR.id.radio_pic:
                tabHost.setCurrentTabByTag("picture");
                break;
            caseR.id.radio_follow:
                tabHost.setCurrentTabByTag("follow");
                break;
            caseR.id.radio_vote:
                tabHost.setCurrentTabByTag("vote");
                break;
 
            default:
                break;
            }
        }
   };


至此就实现了一个自定义的“TabHost”,接下来再添加那个移动的特效

页面上的 
2012033100363827.png 是一个RelativeLayout布局,我只是在这个layout上面添加了一个ImageView,然后当点击的时候,移动它的位置来实现效果

?
代码片段,双击复制
01
02
03
04
05
06
07
08
09
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
privateOnCheckedChangeListener checkedChangeListener = newOnCheckedChangeListener() {
 
        @Override
        publicvoid onCheckedChanged(RadioGroup group, intcheckedId) {
            switch(checkedId) {
            caseR.id.radio_news:
                tabHost.setCurrentTabByTag("news");
//                moveFrontBg(img, startLeft, 0, 0, 0);
                MoveBg.moveFrontBg(img, startLeft, 0,0,0);
                startLeft = 0;
                break;
            caseR.id.radio_topic:
                tabHost.setCurrentTabByTag("topic");
                MoveBg.moveFrontBg(img, startLeft, img.getWidth(), 0,0);
                startLeft = img.getWidth();
                break;
            caseR.id.radio_pic:
                tabHost.setCurrentTabByTag("picture");
                MoveBg.moveFrontBg(img, startLeft, img.getWidth() * 2,0,0);
                startLeft = img.getWidth() * 2;
                break;
            caseR.id.radio_follow:
                tabHost.setCurrentTabByTag("follow");
                MoveBg.moveFrontBg(img, startLeft, img.getWidth() * 3,0,0);
                startLeft = img.getWidth() * 3;
                break;
            caseR.id.radio_vote:
                tabHost.setCurrentTabByTag("vote");
                MoveBg.moveFrontBg(img, startLeft, img.getWidth() * 4,0,0);
                startLeft = img.getWidth() * 4;
                break;
 
            default:
                break;
            }
        }
   };

此处要记住移动的初始位置和起始位置就行了。Y坐标轴上不变,只横向移动。至此,这个功能实现完了

四、顶部按下效果实现

顶部和底部那个自定义控件的实现效果大体是一样的,唯一不同的就是,这个移动的不再是ImageView,而是一个TextView,在移动完成之后还需要改变这个TextView上的文字,仅此而已,而已文件如下layout_news.xml
?
代码片段,双击复制
01
02
03
04
05
06
07
08
09
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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
<?xml version="1.0"encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
   android:layout_width="fill_parent"
   android:layout_height="fill_parent"
   android:orientation="vertical">
 
   <RelativeLayout
        android:id="@+id/layout_top"
        android:layout_width="match_parent"
        android:layout_height="40dip"
        android:background="#990000">
 
        <ImageView
            android:id="@+id/img_netease_top"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:layout_marginLeft="10dip"
            android:src="@drawable/netease_top"/>
 
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:layout_toRightOf="@+id/img_netease_top"
            android:text="@string/news_top_left_text"
            android:textColor="@android:color/white"
            android:textSize="20sp"/>
 
        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentRight="true"
            android:src="@drawable/duoyun"/>
   </RelativeLayout>
 
   <RelativeLayout
        android:id="@+id/layout_title_bar"
        android:layout_width="fill_parent"
        android:layout_height="35dip"
        android:background="@android:color/white"
        android:paddingLeft="10dip"
        android:paddingRight="10dip">
 
        <LinearLayout
            android:layout_width="fill_parent"
            android:layout_height="match_parent"
            android:orientation="horizontal">
 
            <RelativeLayout
                android:id="@+id/layout"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_weight="1">
 
                <TextView
                    android:id="@+id/tv_title_bar_news"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_centerInParent="true"
                    android:text="@string/title_news_category_tops"/>
            </RelativeLayout>
 
            <RelativeLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_weight="1">
 
                <TextView
                    android:id="@+id/tv_title_bar_sport"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_centerInParent="true"
                    android:text="@string/title_news_category_sport"/>
            </RelativeLayout>
 
            <RelativeLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_weight="1">
 
                <TextView
                    android:id="@+id/tv_title_bar_play"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_centerInParent="true"
                    android:text="@string/title_news_category_play"/>
            </RelativeLayout>
 
            <RelativeLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_weight="1">
 
                <TextView
                    android:id="@+id/tv_title_bar_finance"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_centerInParent="true"
                    android:text="@string/title_news_category_finance"/>
            </RelativeLayout>
 
            <RelativeLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_weight="1">
 
                <TextView
                    android:id="@+id/tv_title_bar_science"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_centerInParent="true"
                    android:text="@string/title_news_category_science"/>
            </RelativeLayout>
 
            <RelativeLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_weight="1">
 
                <TextView
                    android:id="@+id/tv_title_bar_more"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_centerInParent="true"
                    android:text="@string/title_news_category_more"/>
            </RelativeLayout>
        </LinearLayout>
   </RelativeLayout>
 
</LinearLayout>


对应的Activity代码TabNewsActivity.java
?
代码片段,双击复制
01
02
03
04
05
06
07
08
09
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
98
99
100
101
102
103
104
105
106
107
108
109
packagecom.and.netease;
 
importcom.and.netease.utils.MoveBg;
 
importandroid.app.Activity;
importandroid.graphics.Color;
importandroid.os.Bundle;
importandroid.view.Gravity;
importandroid.view.View;
importandroid.view.View.OnClickListener;
importandroid.widget.RelativeLayout;
importandroid.widget.RelativeLayout.LayoutParams;
importandroid.widget.TextView;
 
publicclass TabNewsActivity extendsActivity {
   RelativeLayout layout;
   TextView tv_front;//需要移动的View
 
   TextView tv_bar_news;
   TextView tv_bar_sport;
   TextView tv_bar_play;
   TextView tv_bar_finance;
   TextView tv_bar_science;
   TextView tv_bar_more;
 
   intavg_width = 0;// 用于记录平均每个标签的宽度,移动的时候需要
 
   @Override
   protectedvoid onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.layout_news);
 
        initViews();
   }
 
   privatevoid initViews() {
        layout = (RelativeLayout) findViewById(R.id.layout_title_bar);
 
        tv_bar_news = (TextView) findViewById(R.id.tv_title_bar_news);
        tv_bar_sport = (TextView) findViewById(R.id.tv_title_bar_sport);
        tv_bar_play = (TextView) findViewById(R.id.tv_title_bar_play);
        tv_bar_finance = (TextView) findViewById(R.id.tv_title_bar_finance);
        tv_bar_science = (TextView) findViewById(R.id.tv_title_bar_science);
        tv_bar_more = (TextView) findViewById(R.id.tv_title_bar_more);
 
        tv_bar_news.setOnClickListener(onClickListener);
        tv_bar_sport.setOnClickListener(onClickListener);
        tv_bar_play.setOnClickListener(onClickListener);
        tv_bar_finance.setOnClickListener(onClickListener);
        tv_bar_science.setOnClickListener(onClickListener);
        tv_bar_more.setOnClickListener(onClickListener);
 
        tv_front = newTextView(this);
        tv_front.setBackgroundResource(R.drawable.slidebar);
        tv_front.setTextColor(Color.WHITE);
        tv_front.setText("头条");
        tv_front.setGravity(Gravity.CENTER);
        RelativeLayout.LayoutParams param = newRelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
        param.addRule(RelativeLayout.CENTER_VERTICAL, RelativeLayout.TRUE);
        layout.addView(tv_front, param);
 
   }
 
   privateOnClickListener onClickListener = newOnClickListener() {
        intstartX;//移动的起始位置
 
        @Override
        publicvoid onClick(View v) {
            avg_width = findViewById(R.id.layout).getWidth();
            switch(v.getId()) {
            caseR.id.tv_title_bar_news:
                MoveBg.moveFrontBg(tv_front, startX, 0,0,0);
                startX = 0;
                tv_front.setText(R.string.title_news_category_tops);
                break;
            caseR.id.tv_title_bar_sport:
                MoveBg.moveFrontBg(tv_front, startX, avg_width, 0,0);
                startX = avg_width;
                tv_front.setText(R.string.title_news_category_sport);
                break;
            caseR.id.tv_title_bar_play:
                MoveBg.moveFrontBg(tv_front, startX, avg_width * 2,0,0);
                startX = avg_width * 2;
                tv_front.setText(R.string.title_news_category_play);
                break;
            caseR.id.tv_title_bar_finance:
                MoveBg.moveFrontBg(tv_front, startX, avg_width * 3,0,0);
                startX = avg_width * 3;
                tv_front.setText(R.string.title_news_category_finance);
                break;
            caseR.id.tv_title_bar_science:
                MoveBg.moveFrontBg(tv_front, startX, avg_width * 4,0,0);
                startX = avg_width * 4;
                tv_front.setText(R.string.title_news_category_science);
                break;
            caseR.id.tv_title_bar_more:
                MoveBg.moveFrontBg(tv_front, startX, avg_width * 5,0,0);
                startX = avg_width * 5;
                tv_front.setText(R.string.title_news_category_more);
                break;
 
            default:
                break;
            }
 
        }
   };
 
}


五、总结

通过这种例子,我个人总结有两点需要掌握,一个是TranslateAnimation类的使用,另一个就是布局文件的嵌套使用,经验多了,慢慢就会有感觉了。以上仅代表我个人的一点点想法和总结,还请各位多多指教。
原创粉丝点击