具有焦点移动动画效果的菜单控件
代码中的注释是最好的文档。
1.首先看一下在Actvity如何调用此控件
package com.example.ptdmoveanimation;
import java.util.HashMap;
import java.util.Map;
import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.RelativeLayout;
import android.widget.TextView;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
RelativeLayout layout = (RelativeLayout)findViewById(R.id.main);
Map<String,View> menus = new HashMap<String,View>();
TextView textView1 = new TextView(this);
textView1.setText("菜单1");
textView1.setBackgroundColor(Color.LTGRAY);
textView1.setGravity(Gravity.CENTER);
TextView textView2 = new TextView(this);
textView2.setText("菜单2");
textView2.setBackgroundColor(Color.LTGRAY);
textView2.setGravity(Gravity.CENTER);
TextView textView3 = new TextView(this);
textView3.setText("菜单3");
textView3.setBackgroundColor(Color.LTGRAY);
textView3.setGravity(Gravity.CENTER);
TextView textView4 = new TextView(this);
textView4.setText("菜单4");
textView4.setBackgroundColor(Color.LTGRAY);
textView4.setGravity(Gravity.CENTER);
TextView textView5 = new TextView(this);
textView5.setText("菜单5");
textView5.setBackgroundColor(Color.LTGRAY);
textView5.setGravity(Gravity.CENTER);
menus.put("menu1",textView2);
menus.put("menu2",textView3);
menus.put("menu3",textView4);
menus.put("menu4",textView5);
/**
* 静态调用方法
*/
Menu menu = ((Menu)findViewById(R.id.main_menu)).setDurationMillis(300).create(menus);
menu.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Log.i("what", v.getTag().toString());
}
});
// /**
// * 动态调用方法
// */
// Menu menu = new Menu(this).create(menus);
// menu.setOnClickListener(new OnClickListener() {
// @Override
// public void onClick(View v) {
// Log.i("what", v.getTag().toString());
//
// }
// });
// //设置参数
// LayoutParams parmas = menu.getLayoutParams(LayoutParams.MATCH_PARENT,80,RelativeLayout.ALIGN_PARENT_BOTTOM);
// layout.addView(menu,parmas);
}
}
和调用android内部控件的方式一样,只不过自己封装了一个map,把菜单中需要的参数传入控件
2.再看一下menu类是如何实现的
/**
*
* Create Date: 2013-4-7
* Title : 菜单控件
* 一般在主布局中使用。父类布局最好用相对布局RelativeLayout,
* Description:对本文件的详细描述,原则上不能少于50字
* @author : qiuchunlong
* @mender :(文件的修改者,文件创建者之外的人)
* Edit Date : modifydate
* @version : 1.0
*/
public class Menu extends FrameLayout {
/**菜单集合**/
private Map<String,View> mMenus = null;
/**焦点元素**/
private LinearLayout mFouceView = null;
/**菜单展示区容器**/
private LinearLayout mShowView = null;
/**菜单分格线,显示菜单边界**/
private View mLineView = null;
/**菜单父容器**/
private LinearLayout mParentView = null;
/**屏幕宽度**/
private int mScreenWidth = 0;
/**分隔线高度**/
private int mLineViewHigh = 5;
/**分隔线颜色**/
private int mLineViewColor = Color.BLUE;
/**动画持续时间**/
private long mDurationMillis = 500;
/**焦点透明度**/
private int mFouceViewAlpha = 80;
/**焦点颜色**/
private int mFouceViewColor = Color.RED;
/**菜单点击监听**/
private OnClickListener listener = null;
public Menu(Context context){
super(context);
init(context);
}
public Menu(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public Menu(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
}
/**
*
* Create Date: 2013-4-7
* Description:初始化参数
* @author : qiuchunlong
* @mender :(文件的修改者,文件创建者之外的人)
* Edit Date : 2013-4-7
* @version : 1.0
* @param context
*/
private void init(Context context){
//初始化屏幕宽度
this.mScreenWidth = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getWidth();
this.mParentView = new LinearLayout(context);
this.mLineView = new View(context);//初始化分隔线
this.mShowView = new LinearLayout(context);//初始化菜单项容器
this.mFouceView = new LinearLayout(context);//初始焦点
}
/**
*
* Create Date: 2013-4-7
* Description:创建菜单控件调用主方法
* @author : qiuchunlong
* @mender :(文件的修改者,文件创建者之外的人)
* Edit Date : 2013-4-7
* @version : 1.0
* @return
*/
public Menu create(Map<String,View> menus){
//非空校验
if(null == menus){
throw new NullPointerException( " menus is null " );
}
//初始化菜单集合
this.mMenus = menus;
//获取菜单数
int menuSize = this.mMenus.size();
//编辑父容器
editParentView();
//编辑分隔线
editLineView();
//编辑展示区容器
editShowView();
//编辑焦点样式
editFouceView(menuSize);
//编辑菜单样式,及对应关系
editMenus(menuSize);
//设置对应关系
mParentView.addView(mLineView);
mParentView.addView(mShowView);
this.addView(mParentView);
this.addView(mFouceView);
return this;
}
@Override
public void setOnClickListener(OnClickListener l) {
super.setOnClickListener(l);
this.listener = l;
}
/**
*
* Create Date: 2013-4-7
* Description:编辑父容器,设置布局格式为纵向显示布局,
* 宽度高度于父类容器相同
* @author : qiuchunlong
* @mender :(文件的修改者,文件创建者之外的人)
* Edit Date : 2013-4-7
* @version : 1.0
*/
private void editParentView(){
mParentView.setOrientation(LinearLayout.VERTICAL);
mParentView.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT));
}
/**
*
* Create Date: 2013-4-7
* Description:编辑分隔线,高度颜色与类变量值相同
* @author : qiuchunlong
* @mender :(文件的修改者,文件创建者之外的人)
* Edit Date : 2013-4-7
* @version : 1.0
*/
private void editLineView(){
mLineView.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,mLineViewHigh));
mLineView.setBackgroundColor(mLineViewColor);
}
/**
*
* Create Date: 2013-4-7
* Description:编辑展示区,横向布局
* @author : qiuchunlong
* @mender :(文件的修改者,文件创建者之外的人)
* Edit Date : 2013-4-7
* @version : 1.0
*/
private void editShowView(){
mShowView.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT));
mShowView.setOrientation(LinearLayout.HORIZONTAL);
}
/**
*
* Create Date: 2013-4-7
* Description:编辑焦点样式,宽度,高度,颜色,透明度
* @author : qiuchunlong
* @mender :(文件的修改者,文件创建者之外的人)
* Edit Date : 2013-4-7
* @version : 1.0
*/
private void editFouceView(int menuSize){
mFouceView.setLayoutParams(new LayoutParams(mScreenWidth/menuSize,LayoutParams.MATCH_PARENT));
mFouceView.setBackgroundColor(mFouceViewColor);
mFouceView.getBackground().setAlpha(mFouceViewAlpha);//设置透明度
}
/**
*
* Create Date: 2013-4-7
* Description:编辑菜单项,设置菜单宽度,高度,位置,移动动画,添加点击监听
* 菜单标记通过onClickListener(View v)中的v.getTag()获取
* @author : qiuchunlong
* @mender :(文件的修改者,文件创建者之外的人)
* Edit Date : 2013-4-7
* @version : 1.0
*/
private void editMenus(int menuSize){
//遍历菜单项
Iterator<Entry<String,View>> it = this.mMenus.entrySet().iterator();
while (it.hasNext()) {
Entry<String, View> menu = it.next();
String key = menu.getKey();//菜单唯一标识
final View menuView = menu.getValue();//菜单view
menuView.setTag(key);//用菜单view装载唯一标识
//设置view布局宽度高度
menuView.setLayoutParams(new ViewGroup.LayoutParams(mScreenWidth/menuSize, LayoutParams.MATCH_PARENT));
//设置点击监听
menuView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
//如果menu设置了点击监听,则调用
if(null != listener){
listener.onClick(menuView);
}
//计算移动距离
int moveDip = mFouceView.getLeft() - menuView.getLeft();
//设置动画移动效果
TranslateAnimation animation = new TranslateAnimation(moveDip,0,0,0);
//动画执行时间
animation.setDuration(mDurationMillis);
//焦点出现位置
mFouceView.layout(menuView.getLeft(),menuView.getTop(),menuView.getRight(),menuView.getBottom()+mLineViewHigh);
//开始动画
mFouceView.startAnimation(animation);
}
});
//把菜单添加到展示区
mShowView.addView(menuView,0);
}
}
/**
*
* Create Date: 2013-4-7
* Title : 返回相对布局中的布局参数,因为要设置菜单项在界面中的位置,所以系统默认选择相对布局。
* Description:对本文件的详细描述,原则上不能少于50字
* @author : qiuchunlong
* @mender :(文件的修改者,文件创建者之外的人)
* Edit Date : modifydate
* @version : 1.0
* params: w:控件宽度
* h:控件高度
* verb:控件位置
*/
public RelativeLayout.LayoutParams getLayoutParams(int w,int h,int verb){
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(w,h);
params.addRule(verb);
return params;
}
public int getLineViewHigh() {
return mLineViewHigh;
}
public Menu setLineViewHigh(int mLineViewHigh) {
this.mLineViewHigh = mLineViewHigh;
return this;
}
public int getLineViewColor() {
return mLineViewColor;
}
public Menu setLineViewColor(int mLineViewColor) {
this.mLineViewColor = mLineViewColor;
return this;
}
public long getDurationMillis() {
return mDurationMillis;
}
public Menu setDurationMillis(long durationMillis) {
this.mDurationMillis = durationMillis;
return this;
}
public int getFouceViewAlpha() {
return mFouceViewAlpha;
}
public Menu setFouceViewAlpha(int mFouceViewAlpha) {
this.mFouceViewAlpha = mFouceViewAlpha;
return this;
}
public int getFouceViewColor() {
return mFouceViewColor;
}
public Menu setFouceViewColor(int mFouceViewColor) {
this.mFouceViewColor = mFouceViewColor;
return this;
}
}
Menu类,继承FrameLayout类,但是自己定义了许多个性化参数,如动画持续时间,颜色样式等
3.最后看一下配置文件
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<com.example.ptdmoveanimation.Menu
android:id="@+id/main_menu"
android:layout_width="match_parent"
android:layout_height="100dip"
android:layout_alignParentBottom="true" >
</com.example.ptdmoveanimation.Menu>
</RelativeLayout>
父布局采用RelativeLayout,为了方便定义菜单控件在布局中的位置。
还有一点 如果给菜单动态设置样式等属性需要通过这种方式,在创建菜单之前调用。
menu.setDurationMillis(300).create(menus);//设置动画持续时间为300ms。
如果还要有个性化需求,只需要扩展Menu源码即可