【Android UI设计与开发】第09期:底部菜单栏(四)Fragment+PopupWindow仿QQ空间最新版底部菜单栏
转载请注明出处:http://blog.csdn.net/yangyu20121224/article/details/9023451
在今天的这篇文章当中,我依然会以实战加理论结合的方式教大家如何设计出自己觉得很炫的UI界面。好的,话不多说,进入正题。今天的这篇文章主要是以仿QQ空间的底部菜单栏效果为主,实现的效果有:
<1>实现了点击按钮时的切换图片效果;
<2>实现了点击按钮时的切换界面效果;
<3>实现了点击中间圆形按钮时弹出菜单以及按钮图片切换效果;
<4>实现了点击空白处和返回键按钮来关闭弹出菜单。
有个地方需要注意的是,弹出菜单栏后,点击里面的选项按钮会导致中间的圆形按钮切换为普通状态,这是因为在实际的项目中,点击菜单选项按钮之后会进入别的界面,所以也就不存在点击了之后圆形的按钮切换为普通的状态效果了,所以这里也不需要太在意。为了实现效果,这里只适配了480x800 hdpi的屏幕大小。
一、效果图
有图才有真相
二、项目结构图
三、代码详细编写
1、主布局界面,activity_main.xml:
<span style="font-size:12px;"><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="fill_parent" android:layout_height="fill_parent" > <FrameLayout android:id="@+id/frame_content" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_above="@+id/frameLayout1" android:layout_alignParentLeft="true" android:layout_alignParentRight="true" android:layout_alignParentTop="true" android:background="#ffffff" > </FrameLayout> <FrameLayout android:id="@+id/frameLayout1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_alignParentLeft="true" android:background="@drawable/toolbar_bg_normal" > <LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_marginTop="1dp" android:gravity="center_horizontal" > <FrameLayout android:id="@+id/layout_friendfeed" android:layout_width="fill_parent" android:layout_height="48dp" android:layout_weight="1" android:background="@drawable/tab_btn_background"> <ImageView android:id="@+id/image_friendfeed" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="top|center" android:layout_marginTop="1.0dip" android:src="@drawable/tab_friendfeed_btn" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="bottom|center" android:layout_marginBottom="6.0dip" android:text="动态" android:textColor="#ffffff" android:textSize="10sp" /> </FrameLayout> <FrameLayout android:id="@+id/layout_myfeed" android:layout_width="fill_parent" android:layout_height="48dp" android:layout_weight="1" android:background="@drawable/tab_btn_background"> <ImageView android:id="@+id/image_myfeed" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="top|center" android:layout_marginTop="1.0dip" android:src="@drawable/tab_myfeed_btn" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="bottom|center" android:layout_marginBottom="6.0dip" android:text="与我想关" android:textColor="#ffffff" android:textSize="10sp" /> </FrameLayout> <FrameLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_weight="1" > </FrameLayout> <FrameLayout android:id="@+id/layout_home" android:layout_width="fill_parent" android:layout_height="48dp" android:layout_weight="1" android:background="@drawable/tab_btn_background"> <ImageView android:id="@+id/image_home" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="top|center" android:layout_marginTop="1.0dip" android:src="@drawable/tab_home_btn" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="bottom|center" android:layout_marginBottom="6.0dip" android:text="我的空间" android:textColor="#ffffff" android:textSize="10sp" /> </FrameLayout> <FrameLayout android:id="@+id/layout_more" android:layout_width="fill_parent" android:layout_height="48dp" android:layout_weight="1" android:background="@drawable/tab_btn_background"> <ImageView android:id="@+id/image_more" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="top|center" android:layout_marginTop="1.0dip" android:src="@drawable/tab_more_btn" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="bottom|center" android:layout_marginBottom="6.0dip" android:text="更多" android:textColor="#ffffff" android:textSize="10sp" /> </FrameLayout> </LinearLayout> </FrameLayout> <ImageView android:id="@+id/toggle_btn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true" android:src="@drawable/toolbar_btn_normal" /> <ImageView android:id="@+id/plus_btn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignTop="@+id/frameLayout1" android:layout_centerHorizontal="true" android:layout_marginTop="6dip" android:src="@drawable/toolbar_plus" /> </RelativeLayout></span>
我觉得这个布局界面是整个项目当中实现起来最复杂的地方,但是把思路理清楚了之后又觉得其实也没有那么复杂,详细说一下我实现的步骤:
<1> 最外层使用的是RelativeLayout,主要是为了容易摆放底部菜单栏的位置;
<2> 然后是一个FrameLayout,主要用来存放显示Fragment的内容,这里的ID取名为frame_content是用来替换Fragment对象的,在后面的代码中会用到;
<3> 最下面的底部菜单栏中外层使用了FrameLayout,之所以使用FrameLayout是为了让底部菜单栏中间的按钮也可以摆放进来,实现一种叠加的效果;
<4> 里面嵌套了LinearLayout,使用它是为了能够使用layout_weight属性,可以用来更好的摆放按钮,还可以实现自适应屏幕的效果(关于自适应屏幕的内容后面会有专题详细讲解)
<5> 最后里面又嵌套了一个FrameLayout,使用它可以很方便的实现图标在上文字在下的效果,最主要的原因是使用它可以很容易的再添加一个消息提醒的小图片(实际的开发中会用到,此项目中没有用到)
2、弹出菜单的布局界面,popwindow_layout.xml:
<span style="font-size:12px;"><?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="fill_parent" android:layout_height="fill_parent" > <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:background="@drawable/popwindow_bg" android:orientation="vertical" tools:ignore="UselessParent" > <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:layout_marginTop="15dp" android:orientation="horizontal" > <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="5dp" android:layout_weight="1" android:orientation="vertical" > <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:layout_marginTop="1.0dip" android:src="@drawable/popwindow_write_btn" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:layout_marginTop="5.0dip" android:shadowColor="#ff000000" android:shadowDx="1.0" android:shadowDy="1.0" android:shadowRadius="1.0" android:text="说说" android:textColor="#ffffffff" android:textSize="13.0dip" /> </LinearLayout> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="5dp" android:layout_weight="1" android:orientation="vertical" > <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:layout_marginTop="1.0dip" android:src="@drawable/popwindow_voice_btn" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:layout_marginTop="5.0dip" android:shadowColor="#ff000000" android:shadowDx="1.0" android:shadowDy="1.0" android:shadowRadius="1.0" android:text="语音" android:textColor="#ffffffff" android:textSize="13.0dip" /> </LinearLayout> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="5dp" android:layout_weight="1" android:orientation="vertical" > <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:layout_marginTop="1.0dip" android:src="@drawable/popwindow_camera_btn" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:layout_marginTop="5.0dip" android:shadowColor="#ff000000" android:shadowDx="1.0" android:shadowDy="1.0" android:shadowRadius="1.0" android:text="照片" android:textColor="#ffffffff" android:textSize="13.0dip" /> </LinearLayout> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="5dp" android:layout_weight="1" android:orientation="vertical" > <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:layout_marginTop="1.0dip" android:src="@drawable/popwindow_picture_btn" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:layout_marginTop="5.0dip" android:shadowColor="#ff000000" android:shadowDx="1.0" android:shadowDy="1.0" android:shadowRadius="1.0" android:text="视频" android:textColor="#ffffffff" android:textSize="13.0dip" /> </LinearLayout> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="5dp" android:layout_weight="1" android:orientation="vertical" > <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:layout_marginTop="1.0dip" android:src="@drawable/popwindow_sign_btn" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:layout_marginTop="5.0dip" android:shadowColor="#ff000000" android:shadowDx="1.0" android:shadowDy="1.0" android:shadowRadius="1.0" android:text="签到" android:textColor="#ffffffff" android:textSize="13.0dip" /> </LinearLayout> </LinearLayout> </LinearLayout> </RelativeLayout></span>
3、其中一个Fragment布局页面,fragment_1.xml:
<span style="font-size:12px;"><?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" > <ImageView android:id="@+id/imageview" android:layout_width="fill_parent" android:layout_height="fill_parent" android:scaleType="fitCenter" android:src="@drawable/xianjian01" > </ImageView> </LinearLayout></span>
4、自定义按钮的资源文件,由于比较简单,就列出其中一个,tab_friendfeed_btn.xml:
<span style="font-size:12px;"><?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:drawable="@drawable/toolbar_friendfeed_pressed" android:state_selected="true"/> <item android:drawable="@drawable/toolbar_friendfeed_normal"/> </selector></span>
5、主Activity界面,MainActivity.java:
<span style="font-size:12px;">package com.yangyu.mycustomtab03; import android.content.Context; import android.graphics.drawable.BitmapDrawable; import android.os.Bundle; import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentTransaction; import android.view.Gravity; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.View.OnClickListener; import android.view.View.OnTouchListener; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.PopupWindow; import android.widget.PopupWindow.OnDismissListener; public class MainActivity extends FragmentActivity implements OnClickListener{ //定义Fragment页面 private FragmentPage1 fragmentPage1; private FragmentPage2 fragmentPage2; private FragmentPage3 fragmentPage3; private FragmentPage4 fragmentPage4; //定义布局对象 private FrameLayout friendfeedFl,myfeedFl,homeFl,moreFl; //定义图片组件对象 private ImageView friendfeedIv,myfeedIv,homeIv,moreIv; //定义按钮图片组件 private ImageView toggleImageView,plusImageView; //定义PopupWindow private PopupWindow popWindow; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); initData(); //初始化默认为选中点击了“动态”按钮 clickFriendfeedBtn(); } /** * 初始化组件 */ private void initView(){ //实例化布局对象 friendfeedFl = (FrameLayout)findViewById(R.id.layout_friendfeed); myfeedFl = (FrameLayout)findViewById(R.id.layout_myfeed); homeFl = (FrameLayout)findViewById(R.id.layout_home); moreFl = (FrameLayout)findViewById(R.id.layout_more); //实例化图片组件对象 friendfeedIv = (ImageView)findViewById(R.id.image_friendfeed); myfeedIv = (ImageView)findViewById(R.id.image_myfeed); homeIv = (ImageView)findViewById(R.id.image_home); moreIv = (ImageView)findViewById(R.id.image_more); //实例化按钮图片组件 toggleImageView = (ImageView)findViewById(R.id.toggle_btn); plusImageView = (ImageView)findViewById(R.id.plus_btn); } /** * 初始化数据 */ private void initData(){ //给布局对象设置监听 friendfeedFl.setOnClickListener(this); myfeedFl.setOnClickListener(this); homeFl.setOnClickListener(this); moreFl.setOnClickListener(this); //给按钮图片设置监听 toggleImageView.setOnClickListener(this); } @Override public void onClick(View v) { switch (v.getId()) { //点击动态按钮 case R.id.layout_friendfeed: clickFriendfeedBtn(); break; //点击与我相关按钮 case R.id.layout_myfeed: clickMyfeedBtn(); break; //点击我的空间按钮 case R.id.layout_home: clickHomeBtn(); break; //点击更多按钮 case R.id.layout_more: clickMoreBtn(); break; //点击中间按钮 case R.id.toggle_btn: clickToggleBtn(); break; } } /** * 显示PopupWindow弹出菜单 */ private void showPopupWindow(View parent){ if (popWindow == null) { LayoutInflater layoutInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); View view = layoutInflater.inflate(R.layout.popwindow_layout,null); // 创建一个PopuWidow对象 popWindow = new PopupWindow(view,LinearLayout.LayoutParams.FILL_PARENT, 200); } // 使其聚集 ,要想监听菜单里控件的事件就必须要调用此方法 popWindow.setFocusable(true); // 设置允许在外点击消失 popWindow.setOutsideTouchable(true); // 设置背景,这个是为了点击“返回Back”也能使其消失,并且并不会影响你的背景 popWindow.setBackgroundDrawable(new BitmapDrawable()); //设置菜单显示的位置 popWindow.showAsDropDown(parent, Gravity.CENTER, 0); //监听菜单的关闭事件 popWindow.setOnDismissListener(new OnDismissListener() { @Override public void onDismiss() { //改变显示的按钮图片为正常状态 changeButtonImage(); } }); //监听触屏事件 popWindow.setTouchInterceptor(new OnTouchListener() { public boolean onTouch(View view, MotionEvent event) { //改变显示的按钮图片为正常状态 changeButtonImage(); return false; } }); } /** * 点击了“动态”按钮 */ private void clickFriendfeedBtn(){ //实例化Fragment页面 fragmentPage1 = new FragmentPage1(); //得到Fragment事务管理器 FragmentTransaction fragmentTransaction = this.getSupportFragmentManager().beginTransaction(); //替换当前的页面 fragmentTransaction.replace(R.id.frame_content, fragmentPage1); //事务管理提交 fragmentTransaction.commit(); friendfeedFl.setSelected(true); friendfeedIv.setSelected(true); myfeedFl.setSelected(false); myfeedIv.setSelected(false); homeFl.setSelected(false); homeIv.setSelected(false); moreFl.setSelected(false); moreIv.setSelected(false); } /** * 点击了“与我相关”按钮 */ private void clickMyfeedBtn(){ // 实例化Fragment页面 fragmentPage2 = new FragmentPage2(); // 得到Fragment事务管理器 FragmentTransaction fragmentTransaction = this.getSupportFragmentManager().beginTransaction(); // 替换当前的页面 fragmentTransaction.replace(R.id.frame_content, fragmentPage2); // 事务管理提交 fragmentTransaction.commit(); friendfeedFl.setSelected(false); friendfeedIv.setSelected(false); myfeedFl.setSelected(true); myfeedIv.setSelected(true); homeFl.setSelected(false); homeIv.setSelected(false); moreFl.setSelected(false); moreIv.setSelected(false); } /** * 点击了“我的空间”按钮 */ private void clickHomeBtn(){ // 实例化Fragment页面 fragmentPage3 = new FragmentPage3(); // 得到Fragment事务管理器 FragmentTransaction fragmentTransaction = this.getSupportFragmentManager().beginTransaction(); // 替换当前的页面 fragmentTransaction.replace(R.id.frame_content, fragmentPage3); // 事务管理提交 fragmentTransaction.commit(); friendfeedFl.setSelected(false); friendfeedIv.setSelected(false); myfeedFl.setSelected(false); myfeedIv.setSelected(false); homeFl.setSelected(true); homeIv.setSelected(true); moreFl.setSelected(false); moreIv.setSelected(false); } /** * 点击了“更多”按钮 */ private void clickMoreBtn(){ // 实例化Fragment页面 fragmentPage4 = new FragmentPage4(); // 得到Fragment事务管理器 FragmentTransaction fragmentTransaction = this.getSupportFragmentManager().beginTransaction(); // 替换当前的页面 fragmentTransaction.replace(R.id.frame_content, fragmentPage4); // 事务管理提交 fragmentTransaction.commit(); friendfeedFl.setSelected(false); friendfeedIv.setSelected(false); myfeedFl.setSelected(false); myfeedIv.setSelected(false); homeFl.setSelected(false); homeIv.setSelected(false); moreFl.setSelected(true); moreIv.setSelected(true); } /** * 点击了中间按钮 */ private void clickToggleBtn(){ showPopupWindow(toggleImageView); //改变按钮显示的图片为按下时的状态 plusImageView.setImageResource(R.drawable.toolbar_plusback); toggleImageView.setImageResource(R.drawable.toolbar_btn_pressed); } /** * 改变显示的按钮图片为正常状态 */ private void changeButtonImage(){ plusImageView.setImageResource(R.drawable.toolbar_plus); toggleImageView.setImageResource(R.drawable.toolbar_btn_normal); } }</span><span style="font-size:18px;"> </span>
6、Fragment其中一个页面,FragmentPage1.java:
package com.yangyu.mycustomtab03; import android.os.Bundle; import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; public class FragmentPage1 extends Fragment{ @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_1, null); } }
到这里整个项目就基本上讲完了,大家还可以为此项目继续完善下去,实现点击菜单选项后实现的效果以及顶部标题栏的实现。对于这个项目,博主还有一个地方不明白,就是针对此项目,在弹出菜单后,有什么好的简单一点的方法将背景置为灰色?我也试了一些方法,但是效果都不是特别的理想,希望读者有什么想法可以给博主留言,大家可以互相交流学习一下。