滑动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
原创粉丝点击