`

Android 学习 之 模仿人人底部导航条

阅读更多

截图见附件:

 

先准备几张图片吧,在附件那里:(注意:倒数第二张图片附件是个9文件,下载完了记得把后缀改成.9.png)

 

1.新建一个工程,爱叫什么名随便哈,这不是重点。

 

我的工程中把main.xml改成了tabmain.xml,因为我的Activity叫TabMain。

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/container_frame">

<!-- android:scrollbarThumbHorizontal="@drawable/scrollbar" -->
<!-- android:scrollbarAlwaysDrawHorizontalTrack="false" -->
<!-- android:scrollbarStyle="outsideOverlay" -->
<!-- android:fadingEdge="horizontal" -->
<!-- android:fadingEdgeLength="5.0dip" -->

<HorizontalScrollView
android:scrollbars="none"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:background="@drawable/horizontal_bg"
android:id="@+id/container_horizontal">
<LinearLayout
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="@dimen/horizontal_height">
</LinearLayout>
</HorizontalScrollView>
<RelativeLayout
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="@dimen/horizontal_height"
android:id="@+id/container_relative">
<ImageButton
android:id="@+id/left_image"
android:layout_alignParentLeft="true"
android:visibility="gone"
android:layout_width="@dimen/imagebutton_width"
android:layout_height="fill_parent"
android:background="@drawable/arrowl" />
<ImageButton
android:id="@+id/right_image"
android:layout_alignParentRight="true"
android:visibility="gone"
android:layout_width="@dimen/imagebutton_width"
android:layout_height="fill_parent"
android:background="@drawable/arrowr" />
</RelativeLayout>

</FrameLayout>

 

 

2.修改AndroidManifest.xml文件:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.ql.app"
android:versionCode="1"
android:versionName="1.0">

<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".TabMain"
android:label="@string/app_name"
android:configChanges="orientation|keyboardHidden|navigation" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

</application>

<uses-permission android:name="android.permission.CHANGE_CONFIGURATION" ></uses-permission>
</manifest>

 

3.在res/values文件夹下新建一个xml文件,attrs.xml

 

<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="custom">
<attr name="arrayId" format="reference" />
</declare-styleable>
</resources>

同样的,新建一个deimens.xml文件

 

<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="horizontal_height">50dip</dimen>
<dimen name="textview_width">120dip</dimen>
<dimen name="textview_size_big">25sp</dimen>
<dimen name="textview_size_small">20sp</dimen>
<dimen name="imagebutton_width">25dip</dimen>
</resources>

3.重点来了,这个是TabMain.java

 

package com.ql.app;

import android.app.Activity;
import android.content.pm.ActivityInfo;
import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.widget.HorizontalScrollView;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.LinearLayout.LayoutParams;

public class TabMain extends Activity{

/**
* 水平滚动容器,内含一个LinearLayout,所有的子控件都在该LinearLayout容器中
* ,因此,获取子控件的时候应该先通过horizontalScrollView.getChildAt(0)获取
* 到该LinearLayout,然后再通过该LinearLayout的getChildAt()方法获取。
*/
private HorizontalScrollView horizontalScrollView;

/**
* horizontalScrollView的唯一子控件容器
*/
private LinearLayout horizontalLinearLayout;

/**
* 左边的箭头控件
*/
private ImageButton leftImage;

/**
* 右边的箭头控件
*/
private ImageButton rightImage;

/**
* 屏幕的宽度值
*/
private int mScreenW;

/**
* horizontalLinearLayout容纳文本控件的总长度
*/
private int mMeasuredW;

/**
* 文本控件字体大小值:大字体
*/
private int textSizeBig;

/**
* 文本控件字体大小值:小字体
*/
private int textSizeSmall;

/**
* 初始化时将被选中的标题索引值
*/
private int mSelectPosition = 3;

/**
* 标题内容数组
*/
// private String[] titleArrays = {"访客"};
// private String[] titleArrays = {"访客","新鲜事"};
// private String[] titleArrays = {"访客","新鲜事","资料"};
private String[] titleArrays = {"访客","新鲜事","资料","留言板","相册","日记","状态","分享","收藏"};

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

if (mSelectPosition < 0) {
throw new ArrayIndexOutOfBoundsException("初始化被选中的标题索引值mSelectPosition不能小于0");
} else if (mSelectPosition >= titleArrays.length) {
throw new ArrayIndexOutOfBoundsException("初始化被选中的标题索引值mSelectPosition不能大于或等于标题总个数");
}

setContentView(R.layout.tabmain);
init();

}

/**
* 初始化
*/
private void init(){
Resources res = getResources();

textSizeBig = (int) res.getDimension(R.dimen.textview_size_big);
textSizeSmall = (int) res.getDimension(R.dimen.textview_size_small);

int textWidth = 0;

mScreenW = getResources().getDisplayMetrics().widthPixels;

horizontalScrollView = (HorizontalScrollView) findViewById(R.id.container_horizontal);
horizontalLinearLayout = (LinearLayout) horizontalScrollView.getChildAt(0);

leftImage = (ImageButton) findViewById(R.id.left_image);
rightImage = (ImageButton) findViewById(R.id.right_image);

int titleLength = titleArrays.length;

// 注意,水平滚动容器中的LinearLayout与普通的LinearLayout不一样
// 我们只能手动配置params的宽度值才能有效果,设置成FILL_PARENt或
// 比例params.weight也不起任何作用,效果都是WRAP_CONTENT。
LayoutParams params = null;

// 对标题长度进行判断,手动设置文本控件的宽度值
switch (titleLength) {
case 1:
textWidth = mScreenW;
break;
case 2:
textWidth = mScreenW >> 1;
break;
case 3:
textWidth = mScreenW / 3;
break;
default:// 当标题数组的长度大于3个的时候才它设置监听
textWidth = (int) res.getDimension(R.dimen.textview_width);
horizontalScrollView.setOnTouchListener(onTouchListener);
break;
}

params = new LinearLayout.LayoutParams(textWidth, LayoutParams.FILL_PARENT);

for (int i = 0; i < titleLength; i++) {
TextView textView = new TextView(this);
textView.setText(titleArrays[i]);
textView.setTextColor(Color.parseColor("#aaaaaa"));

if (i == mSelectPosition) {

// 设置被选中的这个文本控件给horizontalLinearLayout
horizontalLinearLayout.setTag(textView);
textView.setTextColor(Color.parseColor("#ffffff"));
textView.setBackgroundResource(R.drawable.tab_select);
textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, textSizeBig);

} else {

textView.setTextColor(Color.parseColor("#aaaaaa"));
textView.setBackgroundDrawable(new BitmapDrawable());
textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, textSizeSmall);

}

textView.setOnClickListener(clickListener);
textView.setGravity(Gravity.CENTER);
horizontalLinearLayout.addView(textView,params);
}

// 当标题数组的长度小于3的时候,每个文本控件都是平铺在屏幕上的
// 只有大于3的时候,进行初始化操作时,才去判断是否要显示箭头
if (titleLength > 3) {

mMeasuredW = titleArrays.length * textWidth;

// 为了判断初始化被选中的文本控件的中心位置是否超过了半个屏幕
int tempInitScrollValue = (int) ((mSelectPosition + 0.5 ) * textWidth) - mScreenW/2;
Log.d("debug", "tempMeasuredW = "+mMeasuredW);

if (mMeasuredW > mScreenW) {
rightImage.setVisibility(View.VISIBLE);
}

if (tempInitScrollValue > 0) {
leftImage.setVisibility(View.VISIBLE);

// 发送消息让horizontalScrollView滚动
Message msg = new Message();
msg.what = 1;
msg.obj = String.valueOf(tempInitScrollValue);
handler.sendMessageDelayed(msg, 200);
}

}
}

private View.OnTouchListener onTouchListener = new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {

switch (event.getAction()) {

// 抬起的时候发送消息去判断是否要显示箭头
case MotionEvent.ACTION_UP:
if(v != null){
handler.sendEmptyMessageDelayed(0, 500);
}
break;
}
return false;
}
};

private Handler handler = new Handler(){
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case 0:

Rect localRect = new Rect();
horizontalScrollView.getLocalVisibleRect(localRect);
Log.d("debug", "horizontalScrollView`s Rect2 > l:"+localRect.left+" , r:"+localRect.right+
" W:"+horizontalLinearLayout.getMeasuredWidth());

// 滑动的x值
int tempScrollX = horizontalScrollView.getScrollX();
Log.d("debug", "scrollX = "+tempScrollX);

// 判断是不是达到了最左边或最右边
if (localRect.left == 0 || tempScrollX == 0) {// 最左边
// 隐藏左箭头框
leftImage.setVisibility(View.GONE);
} else {
leftImage.setVisibility(View.VISIBLE);
}

if (localRect.right == mMeasuredW || tempScrollX == mMeasuredW - mScreenW) {// 最右边
// 隐藏右箭头框
rightImage.setVisibility(View.GONE);
} else {
rightImage.setVisibility(View.VISIBLE);
}

break;

case 1:
horizontalScrollView.smoothScrollBy(Integer.parseInt((String)msg.obj), 0);
break;

}



};
};

OnClickListener clickListener = new OnClickListener() {

@Override
public void onClick(View v) {
// 点击的时候,从horizontalLinearLayout中获取未点击前那个
// 被选中的文本控件对象,并变换其颜色,背景,字体大小
TextView beforeView = (TextView) horizontalLinearLayout.getTag();
beforeView.setTextColor(Color.parseColor("#aaaaaa"));
beforeView.setBackgroundDrawable(new BitmapDrawable());
beforeView.setTextSize(TypedValue.COMPLEX_UNIT_SP, textSizeSmall);

// 变换被点击文本控件的颜色,背景,字体大小
TextView clickTextView = ((TextView)v);
clickTextView.setTextColor(Color.parseColor("#ffffff"));
clickTextView.setBackgroundResource(R.drawable.tab_select);
clickTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, textSizeBig);

// 把当前被点击的文本控件设置给horizontalLinearLayout
horizontalLinearLayout.setTag(clickTextView);

// 当标题控件个数大于3的时候才去判断滚动与否
if (titleArrays.length > 3) {
scroll(v);
}

}
};

private void scroll(View v){
Rect vRect = new Rect();
v.getLocalVisibleRect(vRect);
// Log.d("debug", "Click View`s vRect > l:"+vRect.left+" , t:"+vRect.top+" , r:"+vRect.right+" , b:"+vRect.bottom);

int[] hScreen = new int[2];
v.getLocationOnScreen(hScreen);
// Log.d("debug", "Click View`s hScreen = ("+hScreen[0]+" , "+hScreen[1]+")");

/*int[] hWindow = new int[2];
v.getLocationInWindow(hWindow);
Log.d("debug", "Click View`s hWindow = ("+hWindow[0]+" , "+hWindow[1]+")");

Rect localRect = new Rect();
horizontalScrollView.getLocalVisibleRect(localRect);
Log.d("debug", "horizontalScrollView`s Rect > l:"+localRect.left+" , t:"+localRect.top
+" , r:"+localRect.right+" , b:"+localRect.bottom);*/

int tempScreenW = getResources().getDisplayMetrics().widthPixels;
int viewW = v.getWidth();

// Log.d("debug", "onClick >> tempScreenW = "+tempScreenW+" viewW = "+viewW);
int scrollValue = 0;
if (vRect.left > 0 && vRect.right == viewW) {

scrollValue = -((tempScreenW-viewW)/2+vRect.left);
// Log.d("debug", "左入 >> scrollValue = "+scrollValue);

} else if ((vRect.left == 0 && vRect.right == viewW)
|| (vRect.left == 0 && vRect.right < viewW)) {

scrollValue = hScreen[0] + viewW/2 -tempScreenW/2;
// Log.d("debug", "屏显,右入 >> scrollValue = "+scrollValue);

}

Message msg = new Message();
msg.what = 1;
msg.obj = String.valueOf(scrollValue);
handler.sendMessageDelayed(msg, 300);
handler.sendEmptyMessageDelayed(0, 500);
}

public void onConfigurationChanged(android.content.res.Configuration newConfig) {
Log.d("debug", "onConfigurationChanged");
switch (newConfig.orientation) {
// 纵向
case ActivityInfo.SCREEN_ORIENTATION_PORTRAIT:
Log.d("debug", "------------------ >> 纵向");
break;

// 横向
case ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE:
Log.d("debug", "------------------ >> 横向");
break;
}
super.onConfigurationChanged(newConfig);
}

}

 

5.好了,大功告成。运行看效果吧 o(∩_∩)o

  • 大小: 32.2 KB
  • 大小: 4.1 KB
  • 大小: 4.1 KB
  • 大小: 309 Bytes
  • 大小: 3.4 KB
分享到:
评论
8 楼 jxr105 2012-01-04  
里面的"SelectPosition"一直没变?
7 楼 jxr105 2011-12-28  
希望源码作为附件上传。
6 楼 jxr105 2011-12-28  
希望源码作为附件上传。
5 楼 ldci3gandroid 2011-12-22  
textWidth
2006her 写道
不错,感谢分享哈。

哈哈 不客气
4 楼 2006her 2011-12-22  
不错,感谢分享哈。
3 楼 ldci3gandroid 2011-09-28  
kooqianfeng 写道

我来评价一下
杯具的小男人!!!

靠,你个贱人,怎么哪都有你的份捏
2 楼 kooqianfeng 2011-09-28  

我来评价一下
杯具的小男人!!!
1 楼 ldci3gandroid 2011-09-27  
竟然没有人评论,真是伤心~

相关推荐

    底部导航条

    在Android应用开发中,底部导航条(Bottom Navigation Bar)是一种常见的设计模式,它允许用户在应用的几个主要功能之间快速切换。"底部导航条"通常包含3到5个图标按钮,每个图标代表一个不同的功能区域,点击后会...

    SwipePlaybarDemo:模仿QQ音乐Android版的底部播放条,可以滑动切歌

    底部播放条的歌曲信息可以滑动切换,并且专辑图会转动 ##看看截图: Dependency - 依赖 Java Development Kit (JDK) 7 + com.android.tools.build:gradle:1.0.0 Android SDK Android SDK Build-tools 21.1.2 Build -...

    Node.js-一个定制的视图组件模仿MaterialDesign底部导航模式

    在本文中,我们将深入探讨如何使用Node.js创建一个定制的视图组件,该组件模仿了Material Design中的底部导航模式。Material Design是Google推出的一种设计语言,它为移动和Web应用程序提供了一套统一的设计规范和...

    android 仿iphone主题之主菜单

    iOS的主菜单通常采用滑动式页面布局,每个页面代表一个应用或功能模块,而Android则是通过抽屉式导航(Navigation Drawer)或者底部导航栏(Bottom Navigation Bar)来展示应用的主要功能。为了在Android上模仿...

    类似安卓的底部动态提示.zipIOS应用例子源码下载

    3. **数据绑定**:为了使底部导航条与应用的功能部分关联,开发者可能需要实现数据绑定或代理协议。这可能涉及到`MVVM`(Model-View-ViewModel)架构,通过`Observable`对象来同步视图状态。 4. **状态管理**:为了...

    Android高级应用源码-ViewPager仿微信分页导航,多Activity载入.zip

    在这个项目中,ViewPager被用来模仿微信的底部导航栏,通过滑动或点击在不同的Activity之间进行切换。 2. **PagerAdapter**:PagerAdapter是ViewPager的数据适配器,它继承自PagerAdapter接口,需要重写`...

    android仿QQ界面

    主页(MainActivity)通常会包含一个底部导航栏,这可以通过使用TabLayout和ViewPager实现。TabLayout可以创建可切换的标签,而ViewPager则用于滑动浏览不同页面。每个标签页可能对应一个不同的Fragment,这是一种轻...

    Node.js-一个适合做多级目录的文件导航栏控件

    标签“Android开发-导航条”可能意味着这个控件的样式或功能与Android应用中的导航条设计有关,尽管标题提到了Node.js,这可能意味着存在一个跨平台的应用,或者至少是开发者可以借鉴的Android设计原则。Android导航...

    仿网易新闻客户端的上面的tab和下面的功能条

    本示例中的"仿网易新闻客户端的上面的tab和下面的功能条"就是一个典型的案例,旨在帮助开发者掌握如何在Android上构建类似网易新闻客户端顶部Tab栏和底部功能导航条。 首先,顶部Tab栏是Android应用中常用的一种...

    Android项目 效果更接近iphone.rar

    5. **导航栏和底部导航**:iOS的顶部导航栏和底部TabBar在Android中可以使用ToolBar和BottomNavigationView来实现,调整它们的样式和行为,如固定的底部导航栏,以及隐藏/显示的顶部导航栏。 其次,关于UX的模仿: ...

    android手机便签

    这包括使用CardView展示每条便签,以及底部导航栏或者抽屉式菜单来切换不同的功能模块。 描述中提到了“内有截图”,这意味着应用可能集成了图像处理功能。Android系统提供MediaStore API,可以用来读取、保存和...

    仿android微信

    在“仿微信”项目中,可能采用了类似微信的底部导航栏,通过切换Fragment来展示不同内容。 3. **聊天界面(Chat Interface)**:聊天界面是微信的核心功能之一,涉及到消息发送、接收、显示以及输入框交互等复杂...

    仿支付宝活动页面导航菜单

    1. **底部导航栏**:这是应用的主要导航元素,通常固定在屏幕底部,包括几个图标按钮,每个代表一个主要功能模块,如“首页”、“购物”、“我的”等。点击后,页面会滑动切换到相应模块。 2. **侧滑弹出菜单**:...

    Android应用源码之仿UCWEB界面源码.zip

    本篇将深入探讨一个Android应用源码,该源码旨在模仿UCWEB的界面设计,从而帮助开发者学习和理解如何在Android平台上构建类似的应用。 首先,我们要明确Android应用的基本结构。一个标准的Android项目通常包括以下...

    Axure组件库 for Android

    这些组件通常包括但不限于:按钮、输入框、滑动条、下拉列表、切换开关、导航抽屉、底部导航栏、悬浮操作按钮(FAB)、通知提示、日期选择器等。每个组件都尽可能地模仿了Android原生控件的样式和行为,确保在设计时...

    多重水波纹发布动画PlusMenu-master.zip

    【Menu】在Android中,Menu通常用于表示应用程序的主操作选项,如汉堡菜单或底部导航栏。在这个项目中,"Menu"可能被赋予了特殊的设计,利用水波纹动画来增强用户体验。 【MultiWaveHeader】和【lobsterpicker】...

    安卓图片多选相关-Android超高仿微信图片选择器2016年3月13日升级版.rar

    - **底部导航栏**:可能包含一个底部导航条,用于切换相册、拍照、预览等不同模式。 - **选择数量限制**:可以设定最多选择的图片数量,超过则提示用户。 9. **文件操作** - **文件读写**:在用户选择图片后,...

    模仿百度贴吧顶部和底部悬浮的效果

    模仿百度贴吧顶部和底部悬浮的效果,效果模仿了在百度过去的几个版本的百度贴吧中的一个界面布局View Layout的效果的,同时该效果特效也可以 实现了悬浮式顶部,还有底部的标题栏的一些常见漂亮的效果,底部的也可以...

    仿百度新闻客户端

    **LinearLayout** 是Android中最基础的布局管理器之一,它按照垂直或水平方向将子视图排列成一条线。在LinearLayout中,每个子视图可以设置权重(weight),通过权重分配多余的空间,使得界面元素能根据屏幕尺寸...

Global site tag (gtag.js) - Google Analytics