仿微信6.0 主界面 导航:左右滑动的ViewPager+渐变色的底部菜单

本项目 封面图:

思路:

body部分用ViewPager ,底部的图片渐变 ,可以调整两张重叠图片的透明度来实现。



1.底部的导航菜单,是自定义的一个布局。代码如下:

package com.sample.wechat.view;

import java.util.ArrayList;
import java.util.List;

import com.sample.wechat.R;




import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Color;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
/**
 * 定制的 组件
 *  描述:
 *  	横向排列N个条目组件
 *  关联Resource:
 *  	layout: 	custom_radio_button.xml
 *  	drawable: 	page_indicator_focused.png		
 */

@SuppressLint("NewApi") public class CustomRadioGroup extends LinearLayout{
	/**
	 * IMAGE/TEXT 	:	条目的图片/文字  
	 * START/DIF	: 	初始值/和目标的差值
	 * R/G/B		:  	目标颜色RGB格式下的R/G/B
	 */
	private static final int TEXT_START_COLOR=Color.GRAY,END_COLOR=Color.parseColor("#45c01a"),
			TEXT_START_R=Color.red(TEXT_START_COLOR),		TEXT_START_G=Color.green(TEXT_START_COLOR),			TEXT_START_B=Color.blue(TEXT_START_COLOR),
			TEXT_DIF_R=Color.red(END_COLOR)-TEXT_START_R,	TEXT_DIF_G=Color.green(END_COLOR)-TEXT_START_G,		TEXT_DIF_B=Color.blue(END_COLOR)-TEXT_START_B;
	;
	//相关的资源ID:
	private final int ID_LAYOUT=R.layout.custom_radio_button,ID_IMAGE_TOP=R.id.custom_radio_button_image_top,ID_IMAGE_BOTTOM=R.id.custom_radio_button_image_botom,ID_TEXT=R.id.custom_radio_button_text,ID_NEWS=R.id.custom_radio_button_news;
	//条目变更监听
	private OnItemChangedListener onItemChangedListener;
	//条目的LinearLayout.LayoutParams
	private LayoutParams itemLayoutParams=new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
	private LayoutInflater inflater;
	//当前选择的条目
	private int checkedIndex=0;
	//条目列表
	private List<RadioButton> lists=new ArrayList<CustomRadioGroup.RadioButton>();
	public CustomRadioGroup(Context c) {
		super(c);
		init();
	}
	public CustomRadioGroup(Context context, AttributeSet attrs) {
		super(context, attrs);
		init();	
	}
	/**
	 * 构造函数里适用的初始化部分
	 */
	private void init() {
		inflater=LayoutInflater.from(getContext());
		itemLayoutParams.weight=1;
		setOrientation(HORIZONTAL);
	}
	/**
	 * @param f 		颜色渐变参考值。
	 */
	private static int getNewColor(float f){
		int newR,newG,newB;
		newR=(int)(TEXT_DIF_R*f)+TEXT_START_R;
		newG=(int)(TEXT_DIF_G*f)+TEXT_START_G;
		newB=(int)(TEXT_DIF_B*f)+TEXT_START_B;
		return Color.rgb(newR, newG, newB);
	}
	/**
	 * 添加条目
	 * @param unSelected 没有选中时的图片
	 * @param selected	 选中时的图片
	 * @param text		 文本内容
	 */
	public void addItem(int unSelected,int selected,String text){
		RadioButton rb=new RadioButton(unSelected,selected,text);
		final int i=lists.size();
		rb.v.setOnClickListener(new OnClickListener() {
			public void onClick(View arg0) {
				setCheckedIndex(i);
			}
		});
		addView(rb.v);
		lists.add(rb);
	}
	/**
	 * 获取选中的条目索引
	 */
	public int getCheckedIndex() {
		return checkedIndex;
	}	
	/**
	 * 两个item 改变透明度
	 * @param leftIndex 	左边的条目索引
	 * @param rightIndex	右边的条目索引
	 * @param alpha			[0,1)透明度
	 */
	public void itemChangeChecked(int leftIndex,int rightIndex,float alpha){
		if (leftIndex<0||leftIndex>=lists.size()||rightIndex<0||rightIndex>=lists.size()) {
			return ;
		}
		RadioButton a=lists.get(leftIndex);
		RadioButton b=lists.get(rightIndex);
		a.top.setAlpha(alpha);
		a.bottom.setAlpha(1-alpha);
		b.top.setAlpha(1-alpha);
		b.bottom.setAlpha(alpha);
		int aColor=getNewColor(1-alpha);
		int bColor=getNewColor(alpha);
		a.text.setTextColor(aColor);
		b.text.setTextColor(bColor);
	}
	/**
	 * 选择制定索引的条目
	 */
	public void setCheckedIndex(int index) {
		for (int i = 0; i < lists.size(); i++) {
			if (i==index) {
				lists.get(i).setCheceked(true);
				lists.get(i).text.setTextColor(END_COLOR);
			}else{
				lists.get(i).setCheceked(false);
				lists.get(i).text.setTextColor(TEXT_START_COLOR);
			}
		}
		this.checkedIndex=index;
		if (this.onItemChangedListener!=null) {
			onItemChangedListener.onItemChanged();
		}
	}
	/**
	 * 设置指定索引的条目的消息数量
	 * @param index 条目的索引 
	 * @param count	消息的数量
	 */
	public void setItemNewsCount(int index,int count){
		lists.get(index).setNewsCount(count);
	}
	
	/**
	 * 设置条目变更监听器
	 * @param onItemChangedListener
	 */
	public void setOnItemChangedListener(OnItemChangedListener onItemChangedListener) {
		this.onItemChangedListener = onItemChangedListener;
	}
	
	/**
	 * 自定义的RadioButton
	 */
    private	class RadioButton {
		View v;				//条目样式
		ImageView top,bottom;	//条目的图片
		TextView text,news;	//条目的文字,消息
		public RadioButton(int unSelected,int selected,String string) {
			v=inflater.inflate(ID_LAYOUT, null);
			top=(ImageView)v.findViewById(ID_IMAGE_TOP);
			bottom=(ImageView)v.findViewById(ID_IMAGE_BOTTOM);
			text=(TextView)v.findViewById(ID_TEXT);
			news=(TextView)v.findViewById(ID_NEWS);
			
			top.setImageResource(unSelected);
			top.setAlpha(1.0f);
			bottom.setImageResource(selected);
			bottom.setAlpha(0.0f);
			text.setText(string);
			news.setVisibility(INVISIBLE);
			v.setLayoutParams(itemLayoutParams);
		}
		/**
		 * 设置消息数量
		 * @param count 消息数量为0,不显示news的TextView,消息数量>0 显示news的TextView
		 */
		void setCheceked(boolean b){
			if (b) {
				top.setAlpha(0.0f);
				bottom.setAlpha(1.0f);
			}else{
				top.setAlpha(1.0f);
				bottom.setAlpha(0.0f);
			}
		}
		
		void setNewsCount(int count){
			if (count<=0) {
				news.setVisibility(INVISIBLE);
			}else {
				news.setText(count+"");
				news.setVisibility(VISIBLE);
			}
		}
	}
	/**
	 * 条目变更监听接口
	 */
	public interface OnItemChangedListener{
		public void onItemChanged();
	}
}

它关联的图片,是一个红色的圆形,而关联的XML文件如下:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" 
    android:background="@android:color/white">
	<LinearLayout 
	    android:id="@+id/custom_radio_button_main"
	    android:layout_width="wrap_content"
	    android:paddingTop="5dp"
	    android:layout_height="54dp"
	    android:layout_centerInParent="true"
	    android:orientation="vertical"
	    android:gravity="center_horizontal"
	    android:background="@android:color/white"
	    android:baselineAligned="false"
	    >
		<FrameLayout 
		    android:layout_width="wrap_content"
		    android:layout_height="wrap_content"
		    >
	   	<ImageView 
            android:id="@+id/custom_radio_button_image_botom"
            android:contentDescription="@string/hello_world"
            android:layout_width="32dp"
            android:layout_height="28dp"
            android:src="@drawable/ic_launcher"
            android:background="@android:color/transparent"
            android:scaleType="fitCenter"
            />
	   	<ImageView 
            android:id="@+id/custom_radio_button_image_top"
            android:contentDescription="@string/hello_world"
            android:layout_width="32dp"
            android:layout_height="28dp"
            android:src="@drawable/ic_launcher"
            android:background="@android:color/transparent"
            android:scaleType="fitCenter"
            />
		</FrameLayout>
	    <TextView 
	        android:id="@+id/custom_radio_button_text"
			android:text="@string/app_name"
			android:layout_width="wrap_content"
			android:layout_height="wrap_content"
			android:gravity="center"
	        />
	</LinearLayout>
	<TextView 
	    android:layout_alignTop="@id/custom_radio_button_main"
	    android:layout_toRightOf="@id/custom_radio_button_main"
	    android:id="@+id/custom_radio_button_news"
	    android:layout_width="20dp"
	    android:layout_height="20dp"
	    android:layout_marginTop="5dp"
	    android:background="@drawable/news_bg"
	    android:layout_marginLeft="-10dp"
	    android:textColor="@android:color/white"
	    android:gravity="center"
	    />

</RelativeLayout>

2. 使用举例

 主布局为:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.sample.wechat.MainActivity" >

    <com.sample.wechat.view.CustomRadioGroup 
        android:id="@+id/main_footer"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        ></com.sample.wechat.view.CustomRadioGroup>
    <android.support.v4.view.ViewPager
        android:id="@+id/main_body"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_above="@id/main_footer"
        ></android.support.v4.view.ViewPager>
</RelativeLayout>

 Activity为:

package com.sample.wechat;

import java.util.ArrayList;
import java.util.List;

import com.sample.wechat.view.CustomRadioGroup;
import com.sample.wechat.view.CustomRadioGroup.OnItemChangedListener;

import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.view.View;
import android.view.ViewGroup;


public class MainActivity extends FragmentActivity {
	private CustomRadioGroup footer;
	private ViewPager body;
	private int[] itemImage={R.drawable.main_footer_message,R.drawable.main_footer_contanct,R.drawable.main_footer_discovery,R.drawable.main_footer_me};
	private int[] itemCheckedImage={R.drawable.main_footer_message_selected,R.drawable.main_footer_contanct_selected,R.drawable.main_footer_discovery_selected,R.drawable.main_footer_me_selected};
	private String[] itemText={"微信","通讯录","发现","我"};
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initContentView();
    }
	public void initContentView() {
		// 底部
		footer=(CustomRadioGroup)findViewById(R.id.main_footer);
		for (int i = 0; i < itemImage.length; i++) {
			footer.addItem(itemImage[i],itemCheckedImage[i],itemText[i]);
		}
		//主体
		body=(ViewPager)findViewById(R.id.main_body);
		body.setAdapter(new BodyPageAdapter());
		final MainBodyPageChangeListener bodyChangeListener=new MainBodyPageChangeListener(footer);
		body.setOnPageChangeListener(bodyChangeListener);
		
		footer.setCheckedIndex(body.getCurrentItem());
		footer.setOnItemChangedListener(new OnItemChangedListener() {
			public void onItemChanged() {
				body.setCurrentItem(footer.getCheckedIndex(),false);
			}
		});
		/**
		 * BUG :显示不出数字。数字尺寸太大
		 */
		footer.setItemNewsCount(1, 10);//设置消息数量
		
	}
    class BodyPageAdapter extends PagerAdapter{
    	private int[] pageLayouts={R.layout.main_body_page_a,R.layout.main_body_page_b,R.layout.main_body_page_c,R.layout.main_body_pager_d};
    	private List<View> lists=new ArrayList<View>();
    	public BodyPageAdapter() {
    		for (int i = 0; i < pageLayouts.length; i++) {
				View v=getLayoutInflater().inflate(pageLayouts[i], null);
				lists.add(v);
			}
    	}
		public int getCount() {
			return lists.size();
		}

		@Override
		public boolean isViewFromObject(View arg0, Object arg1) {
			// TODO Auto-generated method stub
			return arg0==arg1;
		}
    	@Override
    	public Object instantiateItem(ViewGroup container, int position) {
    		View v=lists.get(position);
    		container.addView(v);
    		return v;
    	}
    	@Override
    	public void destroyItem(ViewGroup container, int position, Object object) {
    		container.removeView(lists.get(position));
    	}
    }
    
    class MainBodyPageChangeListener implements OnPageChangeListener{
    	private CustomRadioGroup customRadioGroup;
    	public MainBodyPageChangeListener(CustomRadioGroup c) {
    		this.customRadioGroup=c;
    	}
    	public void onPageScrollStateChanged(int arg0) {
    	}
    	public void onPageScrolled(int arg0, float arg1, int arg2){
    		if (arg1!=0.0f) {
    			int right,left;
    			if (arg0==customRadioGroup.getCheckedIndex()) {
    				//方向向右
    				left=customRadioGroup.getCheckedIndex();
    				right=customRadioGroup.getCheckedIndex()+1;
    			}else{
    				//方向向左
    				left=customRadioGroup.getCheckedIndex()-1;
    				right=customRadioGroup.getCheckedIndex();
    				
    			}
    			customRadioGroup.itemChangeChecked(left, right, arg1);
    		}else{
    			customRadioGroup.setCheckedIndex(arg0);
    		}
    	}
    	public void onPageSelected(int arg0){
    	}

    }

}

部分,问题说明:

1.源码是一个Eclipse项目,使用的编码格式为UTF-8

2.设置透明度,对API的要求大于11。

源码链接:项目源代码 下载

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值