Android自定义控件之实现类似文件夹顶部的层层显示的横栏效果
2015-11-17 18:03
531 查看
目的概述
要实现的控件效果如图(本图来自小米3)[code]如果说大家之前实现过的这种控件的,非常希望能和大家交流学习一下。 或者说如果大家知道类似这种效果的开源控件,也非常希望能够告知一下。谢谢!!
思路演化
先讲一下我一开始的思路一开始我的想法是定义一个LinearLayout,不断在里面添加TextView的控件,在onlayout()方法中进行TextView的布局,并滑动到最尾端
滑动的话,然后通过Scroller实现滚动,当然滚动效果不是很好
TextView点击事件,因为与滑动冲突,通过GestureDetector很好解决了这两者的关系
但是上面这种的效果不是很好,而且还涉及到了布局边缘位置的判断 ,处理得也不是很好。接下来讲一下我现在的实现方式,比较简单,主要采用了HorizontalScrollView布局实现
通过向HorizontalScrollView添加TextView,并滑动到最尾端
由于采用HorizontalScrollView,滑动与点击事件之间的冲突已经被解决,也不用进行边缘判断
进一步改造,实现第一个标签不动,只是其余标签滑动的效果。看了一下小米对于这个布局的实现即可明白,在最外层添加一个RelativeLayout,子布局为HorizontalScrollView,并添加第一个布局标签固定在左边遮挡住HorizontalScrollView的第一个标签即可
最后补充一点关于标签TextView右边箭头的实现,通过自定义一个继承TextView的控件,并在onDraw()方法中画出这样一条路径
代码实现
[code]通过上面思路的讲解,下面展现实现的代码及效果图
标签TabView
[code]public class TabView extends TextView { /** * 背景颜色 */ private int mBgColor; /** * 线段颜色 */ private int mLineColor; /** * 画笔 */ private Paint mPaint; /** * 路径 */ private Path mPath; @Override protected void onDraw(Canvas canvas) { // TODO Auto-generated method stub super.onDraw(canvas); // 清除上次路径 mPaint.setColor(mBgColor); canvas.drawPath(mPath, mPaint); mPaint.setColor(mLineColor); mPath.reset(); mPath.moveTo(getWidth() - 20 - getHeight() / 2, 0); mPath.lineTo(getWidth() - 20, getHeight() / 2); mPath.lineTo(getWidth() - 20 - getHeight() / 2, getHeight()); canvas.drawPath(mPath, mPaint); } public void setTab(String tab) { setText(tab); } /** * 初始化属性 */ private void init() { setGravity(Gravity.CENTER_VERTICAL); setMaxLines(1); mBgColor = getContext().getResources().getColor( R.color.TabBackGroundColor); mLineColor = getContext().getResources().getColor(R.color.TabLineColor); setBackgroundColor(mBgColor); mPath = new Path(); mPaint = new Paint(); mPaint.setStrokeWidth(2); mPaint.setStyle(Paint.Style.STROKE); } public TabView(Context context) { this(context, null); } public TabView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public TabView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } }
布局FlowLayout
[code]public class FlowLayout extends RelativeLayout implements View.OnClickListener { /** * Tab集合 */ private List<String> mTabs; /** * 存放Tab的横向HorizontalScrollView */ private HorizontalScrollView mHsv; /** * 横向HorizontalScrollView的子布局 */ private LinearLayout mHsvInnerLayout; /** * 添加一个新的标签 * * @param text */ public void addTab(String text) { mTabs.add(text); if (getHsvInnerLayoutChildCount() == 0) { // 为什么add的TextView的text没有居中,因为在addview后,高度为最高,再后来addview后,高度增加 // 添加了该tv,导致scrolleView最后面的View显示不全 addView(getTabView(text)); } mHsvInnerLayout.addView(getTabView(text)); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { super.onLayout(changed, l, t, r, b); // 滑到尾端 mHsv.smoothScrollTo(mHsvInnerLayout.getWidth(), 0); } /** * 获取mHsvInnerLayout的子View数量 * * @return */ private int getHsvInnerLayoutChildCount() { return mHsvInnerLayout.getChildCount(); } /** * 根据tab生产View * * @param tab * @return */ private View getTabView(String tab) { View view = LayoutInflater.from(getContext()).inflate( R.layout.item_file_tag, this, false); TabView tv = (TabView) view.findViewById(R.id.item_tag); tv.setTab(tab); tv.setTag(tab); // 用于点击事件的判断 ((TextView) tv).setTextColor(getTabColorStateList()); tv.setOnClickListener(this); LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); view.setLayoutParams(params); return view; } private void init() { mTabs = new ArrayList<String>(); // 设置子view垂直方向上居中 setGravity(Gravity.CENTER_HORIZONTAL); setBackgroundColor(getResources().getColor(R.color.TabBackGroundColor)); initHSV(); } /** * 初始化HorizontalScrollView */ private void initHSV() { mHsv = new HorizontalScrollView(getContext()); // 隐藏滚动条 mHsv.setHorizontalScrollBarEnabled(false); LayoutParams mHsvParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); mHsvParams.rightMargin = 50; mHsvInnerLayout = new LinearLayout(getContext()); LayoutParams mHsvInnerLayoutParams = new LayoutParams( LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT); mHsvInnerLayout.setGravity(Gravity.CENTER_VERTICAL); // 添加子View mHsv.addView(mHsvInnerLayout, mHsvInnerLayoutParams); addView(mHsv, mHsvParams); } public FlowLayout(Context context) { this(context, null); } public FlowLayout(Context context, AttributeSet attrs) { this(context, attrs, 0); } public FlowLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } /** * 获取ColorStateList对象 * * @return */ private ColorStateList getTabColorStateList() { ColorStateList csl = new ColorStateList(new int[][] { { android.R.attr.state_pressed }, { -android.R.attr.state_pressed } }, new int[] { Color.BLACK, Color.GRAY }); return csl; } private onTabClickListener mOnTabClickListener; /** * tab点击事件接口 */ public interface onTabClickListener { void onTabClick(String tab); } public void setOnTabClickListener(onTabClickListener l) { this.mOnTabClickListener = l; } @Override public void onClick(View v) { String tab = (String) v.getTag(); if (tab == null) return; if (mOnTabClickListener != null) { mOnTabClickListener.onTabClick(tab); } // 移除后面Tab int index = mTabs.indexOf(tab); int size = mTabs.size(); // 不作处理 if (index == -1 || index == size - 1) { return; } for (int i = size - 1; i > index; i--) { mHsvInnerLayout.removeViewAt(i); mTabs.remove(i); } } }
效果
Demo下载地址
总结
总体来说没什么难度,但是还是值得学习记录一下过程思想最后
最近可能开始要忙了,不过最近在学习Android开源框架Volley,所以接下来将会对记录一下我对Volley的理解。对Volley的用法,源码,设计模式,HTTP,自定义异常等方面做个记录最后呢,如果你有其他思路或者开源控件,非常期待你的分享,谢谢。
如果本篇文章有哪里错误不足之处,或者哪方面可以做更好的封装,也希望能够指出,一起探讨学习。
相关文章推荐
- android高德地图调用定位显示
- 利用Framework7的初次使用,使用教程,环境搭建
- CoverFlow一个实例demo
- Android NDK之JNI陷阱
- 【android学习】Android权限permission
- MVP模式在Android中的应用之图片展示选择功能的框架设计
- Android手机出现"已安装了存在签名冲突的同名数据包"的原因及解决办法
- A20 实现 红外 开关机
- android自己用到的第三方库汇总
- android 反编译smali 学习
- Android之手机现场保护Saving activity state
- Android 广播大全 Intent Action 事件
- 浅谈Android中Activity的生命周期和加载模式
- 【android实战经验】关闭Fragment的方法
- Android学习之使用SQLite实现简单的(CRUD)增删改查
- 在线更新Android SDK
- Android System Property分析(2):property_service
- Android 多线程,线程池的使用
- Android dp转换像素问题
- RecylerViewd的Item高度自适应,Scrollview 嵌套 RecyclerView 及在Android 5.1版本滑动时 惯性消失问题