![](https://img.haomeiwen.com/i5186985/5c06304a1c948378.gif)
这是一个采用adapter设计模式实现的下拉列表选择效果;可以大致分为三步来实现;
1.最上边tab栏
2.阴影背景
3.内容区域
这里自定义容器继承的是LinearLayout,在构造方法中就要去初始化布局,将tab栏、内容区域、阴影背景实例化并添加到布局容器中;
/**
* 初始化布局
*/
private void initLayout() {
//创建tab
mTabView = new LinearLayout(mContext);
mTabView.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));
mTabView.setBackgroundColor(Color.BLUE);
addView(mTabView);
//创建内容容器
mContentView = new FrameLayout(mContext);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, 0);
params.weight = 1;
addView(mContentView);
//创建阴影
mShadowView = new View(mContext);
mShadowView.setBackgroundColor(0x88888888);
mContentView.addView(mShadowView);
//设置阴影透明
mShadowView.setAlpha(0f);
//设置阴影隐藏
mShadowView.setVisibility(GONE);
//设置阴影点击事件 点击阴影关闭
mShadowView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
closeMenu();
}
});
//创建列表内容容器
listContentView = new FrameLayout(mContext);
listContentView.setBackgroundColor(Color.WHITE);
mContentView.addView(listContentView);
}
初始化完毕后,还需要重新设置内容区域的高度;最好是根据自定义容器高度的百分比来进行设置;
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//重新设置内容布局显示的高度
int height = MeasureSpec.getSize(heightMeasureSpec);
if (mContentViewHeight == 0 && height > 0) {
//onMeasure方法会被多次调用
mContentViewHeight = (int) ((height * 65f) / 100);
ViewGroup.LayoutParams params = listContentView.getLayoutParams();
params.height = mContentViewHeight;
listContentView.setLayoutParams(params);
//一开始设置内容布局位移 隐藏掉
listContentView.setTranslationY(-mContentViewHeight);
}
}
在自定义容器中提供一个setAdapter方法,并定义一个抽象的BaseMenuAdapter类,提供getCount、getTabView、getContentView等方法;在外部调用setAdapter时根据需求去实例化一个BaseMenuAdapter子类;
/**
* 设置适配器
*
* @param adapter
*/
public void setAdapter(BaseMenuAdapter adapter) {
if (adapter == null) {
return;
}
this.menuAdapter = adapter;
int count = menuAdapter.getCount();
for (int i = 0; i < count; i++) {
View tabView = menuAdapter.getTabView(i, mTabView);
LinearLayout.LayoutParams tabParams = new LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.WRAP_CONTENT);
tabParams.weight = 1;
tabView.setLayoutParams(tabParams);
mTabView.addView(tabView);
//设置tab点击事件
tabClick(i);
View contentView = menuAdapter.getContentView(i, listContentView);
listContentView.addView(contentView);
//一开始将内容布局隐藏掉
contentView.setVisibility(GONE);
}
}
在setAdapter方法中根据getCount方法返回的数量通过getTabView和getContentView获取到对应的tab view和内容view并添加到对应的布局容器中,同时为tab view添加对应的点击事件;
/**
* tab点击事件
*
* @param position
*/
private void tabClick(final int position) {
View childAt = mTabView.getChildAt(position);
childAt.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (mCurrentPosition == -1) {
//打开
openMenu(position);
} else {
if (mCurrentPosition == position) {
//关闭
closeMenu();
} else {
//切换 隐藏之前的
View childAt = listContentView.getChildAt(mCurrentPosition);
childAt.setVisibility(GONE);
menuAdapter.closeMenu(mTabView.getChildAt(mCurrentPosition));
//显示当前选择的
mCurrentPosition = position;
childAt = listContentView.getChildAt(mCurrentPosition);
childAt.setVisibility(VISIBLE);
menuAdapter.openMenu(mTabView.getChildAt(mCurrentPosition));
}
}
}
});
}
在点击事件中判断如果当前内容菜单是关闭的那就调用openMenu方法打开,在打开的时候设置相应的位移和透明度动画效果;
/**
* 打开
*
* @param position
*/
private void openMenu(final int position) {
if (isAnimatorExcute) {
return;
}
listContentView.setVisibility(VISIBLE);
View childAt = listContentView.getChildAt(position);
childAt.setVisibility(VISIBLE);
//平移动画
ObjectAnimator translationY = ObjectAnimator.ofFloat(listContentView, "translationY", -mContentViewHeight, 0);
translationY.setDuration(DURACTION_TIME);
translationY.start();
//透明度动画
mShadowView.setVisibility(VISIBLE);
ObjectAnimator alpha = ObjectAnimator.ofFloat(mShadowView, "alpha", 0f, 1f);
alpha.setDuration(DURACTION_TIME);
alpha.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
super.onAnimationStart(animation);
isAnimatorExcute = true;
//改变tab字体颜色
menuAdapter.openMenu(mTabView.getChildAt(position));
}
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
mCurrentPosition = position;
isAnimatorExcute = false;
}
});
alpha.start();
}
如果当前内容菜单是打开的,点击的位置就只之前的位置就调用closeMenu方法关闭当前菜单,如果点击的位置不是当前的位置就切换菜单内容;
/**
* 关闭
*/
public void closeMenu() {
if (isAnimatorExcute) {
return;
}
//平移动画
ObjectAnimator translationY = ObjectAnimator.ofFloat(listContentView, "translationY", 0, -mContentViewHeight);
translationY.setDuration(DURACTION_TIME);
translationY.start();
//透明度动画
ObjectAnimator alpha = ObjectAnimator.ofFloat(mShadowView, "alpha", 1f, 0f);
alpha.setDuration(DURACTION_TIME);
alpha.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
super.onAnimationStart(animation);
isAnimatorExcute = true;
//改变tab字体颜色
menuAdapter.closeMenu(mTabView.getChildAt(mCurrentPosition));
}
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
View childAt = listContentView.getChildAt(mCurrentPosition);
childAt.setVisibility(GONE);
listContentView.setVisibility(GONE);
mShadowView.setVisibility(GONE);
mCurrentPosition = -1;
isAnimatorExcute = false;
}
});
alpha.start();
}
public abstract class BaseMenuAdapter {
/**
* 获取总条数
* @return
*/
public abstract int getCount();
/**
* 获取tabview
* @return
*/
public abstract View getTabView(int position,ViewGroup parent);
/**
* 获取内容view
* @return
*/
public abstract View getContentView(int position,ViewGroup parent);
/**
* 打开内容
* @param childAt
*/
public void openMenu(View childAt) {
}
/**
* 关闭内容
* @param childAt
*/
public void closeMenu(View childAt) {
}
public interface MenuClickListener{
void menuClickListener(int position,String value);
}
protected MenuClickListener listener;
public void setOnMenuClickListener(MenuClickListener listener){
this.listener=listener;
}
}
对于打开或者关闭时,tab字体或者箭头的处理,可以在BaseMenuAdapter 子类的openMenu和closeMenu方法中进行处理;
public class ListScreenMenuAdapter extends BaseMenuAdapter {
private Context mContext;
public ListScreenMenuAdapter(Context mContext) {
this.mContext = mContext;
}
private String[] items = {"类型", "品牌", "价格", "更多"};
@Override
public int getCount() {
return items.length;
}
@Override
public View getTabView(int position, ViewGroup parent) {
View view = LayoutInflater.from(mContext).inflate(R.layout.tab_item_view, parent, false);
TextView tabTxt = (TextView) view.findViewById(R.id.tab_txt);
tabTxt.setText(items[position]);
return view;
}
@Override
public View getContentView(int position, ViewGroup parent) {
//可以根据不同类型实例化不同的view
View view = null;
if (items[position].equals("类型")) {
view = createListView(position, parent);
} else {
view = createView(position, parent);
}
return view;
}
/**
* 创建列表布局view
* @param position
* @param parent
* @return
*/
private View createListView(int position, ViewGroup parent) {
View view = LayoutInflater.from(mContext).inflate(R.layout.leixi_layout, parent, false);
RecyclerView recyclerView = (RecyclerView) view.findViewById(R.id.recycler_view);
recyclerView.setLayoutManager(new LinearLayoutManager(mContext));
LexingAdapter adapter = new LexingAdapter(mContext);
recyclerView.setAdapter(adapter);
//条目点击事件
adapter.setOnItemClickListener(new LexingAdapter.ItemClickListener() {
@Override
public void itemClickListener(int position, String value) {
if(listener!=null){
listener.menuClickListener(position,value);
}
}
});
return view;
}
/**
* 创建布局
*
* @param position
* @param parent
* @return
*/
private View createView(final int position, ViewGroup parent) {
View view = LayoutInflater.from(mContext).inflate(R.layout.content_item_view, parent, false);
TextView contentTxt = (TextView) view.findViewById(R.id.content_txt);
contentTxt.setText(items[position]);
contentTxt.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(listener!=null){
listener.menuClickListener(-1,items[position]);
}
}
});
LinearLayout conentLayout = (LinearLayout) view.findViewById(R.id.conent_layout);
conentLayout.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
}
});
return view;
}
@Override
public void openMenu(View childAt) {
super.openMenu(childAt);
setTabColor(childAt, Color.RED);
}
@Override
public void closeMenu(View childAt) {
super.closeMenu(childAt);
setTabColor(childAt, Color.BLACK);
}
/**
* 设置选择颜色
*
* @param childAt
* @param color
*/
private void setTabColor(View childAt, int color) {
if (childAt instanceof LinearLayout) {
LinearLayout layout = (LinearLayout) childAt;
int childCount = layout.getChildCount();
if (childCount > 0) {
View childAt1 = layout.getChildAt(0);
if (childAt1 instanceof TextView) {
TextView tv = (TextView) childAt1;
tv.setTextColor(color);
}
}
}
}
}
点击内容区域选择的内容通过BaseMenuAdapter中的MenuClickListener接口进行回调;
/**
* 内容菜单点击事件
* @param listener
*/
public void menuClick(BaseMenuAdapter.MenuClickListener listener){
menuAdapter.setOnMenuClickListener(listener);
}
网友评论