滑动tab栏,有点类似网易的,上次写的真不行,感觉对别人没什么帮助,写个最新的吧
来源:互联网 发布:厦门seo公司陈仁潘 编辑:程序博客网 时间:2024/06/07 12:51
先上图片
这是菜单栏,可以滑动,点击非当前选中项,底部的橙色条可以滑动到选中项的底部。网易用的是红色,这用的是橙色。
控件可定制的参数
1,不可滚动时最大项数。
菜单项多的时候才滚动,少的时候当然不让他滚动啦,这个控件用到的参数是
maxNoScrollNum
2,菜单项的高度buttonHeight
3,橙色条宽度和每个菜单项是一样的,但是它有padding值,图片中橙色条两边是有缩短的。
offValue
4,显示项多的时候,初始化时第maxNoScrollNum + 1项向左偏移的距离,这样用户才会知道有更多项可以选择。offForScroll
5,橙色条的高度下面直接上代码,代码注释的很详细,阅读起来应该没困难dividerHeight
public class HorizontalMenuView extends HorizontalScrollView implements View.OnClickListener { private List<String> contents; // 提示内容 private int screenWidth = 0; // 屏幕宽度 private MCallBack mCallBack; // 请求回调 private int itemWidth = 0;//每一项的宽度 private LinearLayout mLayoutContent;//全局布局 private LinearLayout mLayoutItem;//按钮集合所在布局 private LinearLayout mLayoutDivider;//底部动画线条所在布局 private ImageView mImageDivider; // 分割线 private List<Button> buttonList; // 按钮的列表 private int offValue = 20;//每一个item下的黄线两端收缩的宽度 private int dividerHeight = -1;//动画线条的高度 private int buttonHeight = -1;//每个按钮的高度 private int maxNoScrollNum = 4;//不可滚动时最大button数,默认为4个 private int offForScroll = 80;//如果能滚动,那初始化时,第maxNoScrollNum + 1项可见的长度,默认为80 private int selectPosition = 0; // 当前选中的位置 public HorizontalMenuView(Context context) { super(context); initView(context); } public HorizontalMenuView(Context context, AttributeSet attrs) { super(context, attrs); initView(context); } private void initView(Context context){ setBackgroundColor(Color.WHITE); setHorizontalScrollBarEnabled(false);//隐藏滑动条 mLayoutContent = (LinearLayout)LayoutInflater.from(context).inflate(R.layout.horizontal_menu_view,null); mLayoutItem = (LinearLayout) mLayoutContent.findViewById(R.id.ll_horizontal_list_view); mLayoutDivider = (LinearLayout) mLayoutContent.findViewById(R.id.ll_divider); addView(mLayoutContent); //获取屏幕信息 DisplayMetrics displayMetrics = this.getContext().getResources().getDisplayMetrics(); screenWidth = displayMetrics.widthPixels; buttonList = new ArrayList<Button>(); } public void append(List<String> items){ contents = items; fullViewWithData(getContext()); } /* * 初始化和刷新数据的入口 */ private void fullViewWithData(Context context){ mLayoutItem.removeAllViews(); mLayoutDivider.removeAllViews(); if (contents == null || contents.size() == 0){ return; } if (contents.size() <= maxNoScrollNum){ itemWidth = screenWidth / contents.size(); }else { itemWidth = (screenWidth - offForScroll) / maxNoScrollNum;//数量多于限制时 if (offForScroll >= itemWidth){//当计算出来的偏移量大于item宽度时,不符合要求,强制设置约为item宽度的一半 itemWidth = (screenWidth - (screenWidth / maxNoScrollNum) / 2) / maxNoScrollNum; } } for (int i = 0; i < contents.size();i++){//添加按钮 View view = initItemView(context,i,contents.get(i)); mLayoutItem.addView(view); } setBtnStyle(this.getContext(), 0, 0); // 初始化 分割线 initDividerView(context); // 添加动画线条 mLayoutDivider.addView(mImageDivider); invalidate();//刷新界面 } /** * 初始化子项 控件 * * @param context 上下文 * @param position 位置 * @param content 内容 */ private View initItemView(Context context, int position, String content) { View itemView = LayoutInflater.from(context).inflate(R.layout.home_biz_menu_item, null); Button mBtnItem = (Button) itemView.findViewById(R.id.btn_trade); if (buttonHeight > 0){ LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) mBtnItem.getLayoutParams(); params.height = buttonHeight; mBtnItem.setLayoutParams(params); } mBtnItem.setOnClickListener(this); mBtnItem.setTag(position); mBtnItem.setText(content); buttonList.add(mBtnItem); LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(itemWidth, ViewGroup.LayoutParams.MATCH_PARENT); itemView.setLayoutParams(params); return itemView; } /** * 设置选中 按钮的 样式 * * @param context 上下文 * @param selectPosition 选中的位置 */ private void setBtnStyle(Context context, int selectPosition, int lastPosition) { if (selectPosition >= buttonList.size()) return; buttonList.get(lastPosition).setTextAppearance(context, R.style.content_text_hint_gray); buttonList.get(selectPosition).setTextAppearance(context, R.style.send_menu_text_orange_style); } /* * 设置 选中的位置 播放动画效果 * * @param targetPosition 目标位置 */ private void setPosition(View v) { int position = (Integer) v.getTag(); Animation animation = getAnimation(position); mImageDivider.startAnimation(animation); this.selectPosition = position;//放在调用getAnimation()方法后面 } // 生成 移动动画 private Animation getAnimation(int position) { //生成动画,注意,动画中的坐标是相对于父布局而非屏幕,这里用到的是scrollView Animation animation = new TranslateAnimation(selectPosition * itemWidth, position * itemWidth, 0, 0); animation.setFillAfter(true); animation.setDuration(300); return animation; } public interface MCallBack { /** * 已选择 的位置 回调 * * @param context 上下文 * @param position 目标位置 */ void select(Context context, int position); } @Override public void onClick(View v) { int position = (Integer) v.getTag(); if (this.selectPosition == position) return; // 设置 按钮的 样式 setBtnStyle(this.getContext(), position, selectPosition); //动画效果 setPosition(v); // 结果回调 if (mCallBack != null) { mCallBack.select(v.getContext(), position); } } /** * 初始化动画线条 * * @param context 上下文 */ private void initDividerView(Context context){ mImageDivider = new ImageView(context); int height; if (dividerHeight > 0){ height = dividerHeight; }else { height = (int) context.getResources().getDimension(R.dimen.dp4); } LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(itemWidth, height); mImageDivider.setImageResource(R.color.color_backgroud_bg); if (offValue > 0){ mImageDivider.setPadding(offValue,0,offValue,0); } mImageDivider.setLayoutParams(params); } /** * 设置回调接口 * * @param mCallBack 接口 */ public void setCallBack(MCallBack mCallBack) { this.mCallBack = mCallBack; } /** * 设置每一个item下的黄线两端收缩的宽度 * * @param offValue 宽度 */ public void setOffValue(int offValue) { this.offValue = offValue; fullViewWithData(getContext()); } /** * 设置动画线条的宽度 * * @param dividerHeight 宽度 */ public void setDividerHeight(int dividerHeight) { this.dividerHeight = dividerHeight; fullViewWithData(getContext()); } /** * 设置按钮的高度 * * @param buttonHeight 高度 */ public void setButtonHeight(int buttonHeight) { this.buttonHeight = buttonHeight; fullViewWithData(getContext()); } /** * 设置不滚动的最大按钮数 * * @param maxNoScrollNum 最大数 */ public void setMaxNoScrollNum(int maxNoScrollNum) { this.maxNoScrollNum = maxNoScrollNum; fullViewWithData(getContext()); } /** * 设置第maxNoScrollNum + 1项可见的长度 * * @param offForScroll 向左偏移的距离 */ public void setOffForScroll(int offForScroll) { this.offForScroll = offForScroll; fullViewWithData(getContext()); } /** * 设置选中的位置 * * @param position 位置 */ public void setSelectPosition(int position) { if (this.selectPosition == position) return; setBtnStyle(this.getContext(), position, selectPosition); setPosition(buttonList.get(position)); }}
整个菜单栏的整体布局,一个LinearLayout放按钮,一个LinearLayout 放动画条,另外加一个分割线<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="wrap_content"> <LinearLayout android:orientation="horizontal" android:id="@+id/ll_horizontal_list_view" android:layout_width="match_parent" android:layout_height="@dimen/dp80"> </LinearLayout> <LinearLayout android:orientation="horizontal" android:id="@+id/ll_divider" android:layout_width="match_parent" android:layout_height="wrap_content"> </LinearLayout> <View android:layout_width="match_parent" android:layout_height="@dimen/dp1" android:background="@color/color_line_horizental" /></LinearLayout>每一个按钮所在的布局<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical"> <Button android:id="@+id/btn_trade" android:layout_width="match_parent" android:layout_height="@dimen/dp80" android:background="@null" android:button="@null" android:checked="true" android:gravity="center" android:singleLine="true" android:textSize="@dimen/dp30" /></LinearLayout>选中时和未选中时的样式<style name="send_menu_text_orange_style"> <item name="android:textColor">#f48400</item> <item name="android:textSize">@dimen/dp30</item> </style><style name="content_text_hint_gray"> <item name="android:textColor">#454545</item> <item name="android:textSize">@dimen/dp30</item> <item name="android:textColorHint">#dddddd</item> </style>说说一下思路吧。这个东西之前项目里有一个不能滑动的,继承的是linearlayout的控件,扩展性不太好,所以才想重写的这个东西。既然要做成滑动的,那就直接继承HorizontalScrollView就可以。
控件内部,所有的按钮放在一个linearlayout内,滑动的线条放在下面一个linearlayout内,然后来一个分割线。写的时候遇见的问题:在写动画的时候,遇见了一个问题,就是动画结束的位置不准确,因为是滑动的,开始做动画的思路是这样的,按钮位置是变化的,所以要根据view对象的getLocationOnScreen()方法获取位置,然后生成动画,这里犯了一个错误,就是我以为动画坐标是根据屏幕位置参数生成的,其实这里不是这么简单,应该是相对于HorizontalScrollView布局的位置来设置的。之前有用到过水平listview控件,所以就意识到应该这么做,然后改写逻辑,问题就解决啦。
这个图片是初始化时的样子,无滑动最大项默认设为4项,这里面是超过4项的,所以能看到第五项向左偏移了。这是滑动后。这是添加的数据只有4项时的效果,不可滑动,4个按钮均分整个屏幕宽度另外补充一下这个和网易tab栏的区别吧。这个控件其实和网易的很相似了,不过有一个较大的区别就是,网易的点击后,如果可以的话,会把选中项放到距离左边一定距离的固定位置。scrollview的smoothScrollTo()方法没有动画效果,如果做成动画效果,大家可以研究一下,这个我也不太清楚,没研究过,scrollview里面有个setAnimation()方法,可能会用到。
0 0
- 滑动tab栏,有点类似网易的,上次写的真不行,感觉对别人没什么帮助,写个最新的吧
- 我感觉没什么可写的
- 没什么好写的!
- 没什么要写的
- 没什么好写的
- 没什么可写的
- 没什么写的
- 可以写博客的感觉真好
- 今天突然感觉不写博客真的不行啦。 搞了两年开发, 啥都没留下
- 暂时没什么好写的
- 没什么好写的啊
- 抽象类+接口+内部类(有点晕 写的自己都感觉不太对)
- 自己写的约瑟夫环的方法,感觉有点笨~~~~
- 自己用c 写的strcat函数 感觉有点作死
- 第一次写对C的感觉!
- 类似网易新闻首页的轮播图,写了个自创的框架
- 关于上次写的计划...
- 近来真的感觉有点无所事事了~~
- 年鉴注册
- 2015年终总结
- sbt,scala,spark配置问题
- 如何解决iOS中更改系统定位权限时候系统设置崩溃的问题
- Eclipse 项目中的包路径变成文件夹目录形式了
- 滑动tab栏,有点类似网易的,上次写的真不行,感觉对别人没什么帮助,写个最新的吧
- Java线程篇(三):线程协作:生产者与消费者问题
- IOS - 隐式动画
- android Studio中关于Gradle的使用注解
- 编程的智慧
- Mysql中TO_DAYS函数
- 白手起家学习数据科学 ——线性回归之“简单线性回归篇”(十一)
- android ui测试uiautomator
- tomcat设置内存溢出配置