承接上一篇文章:Android高仿网易新闻客户端之首页,今天来实现动态添加标签效果。

动态标签页是一个流式布局,实现了宽度自动换行高度自动分配的功能,代码如下:

FlowLayout.java

package com.jackie.neteasenews;import android.content.Context;import android.util.AttributeSet;import android.view.View;import android.view.ViewGroup;import java.util.ArrayList;import java.util.List;/** * Created by Jackie on 2015/12/30. * 流式布局 */public class FlowLayout extends ViewGroup {    public FlowLayout(Context context) {        //new FlowLayout的时候会调用        this(context, null);    }    public FlowLayout(Context context, AttributeSet attrs) {        //在布局文件中定义一个自定义View的时候(没有用到自定义属性)        this(context, attrs, 0);    }    public FlowLayout(Context context, AttributeSet attrs, int defStyleAttr) {        //在布局文件中定义一个自定义View的时候(用到自定义属性)        super(context, attrs, defStyleAttr);    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        /**         * MeasureSpec.EXACTLY        //match_parent或者精确值           MeasureSpec.AT_MOST        //warp_content 这种情况的View的宽度和高度是需要我们自己计算的           MeasureSpec.UNSPECIFIED   //少见,子控件想要多大就多大         */        int sizeWidth = MeasureSpec.getSize(widthMeasureSpec);        int sizeHeight = MeasureSpec.getSize(heightMeasureSpec);        int modeWidth = MeasureSpec.getMode(widthMeasureSpec);        int modeHeight = MeasureSpec.getMode(heightMeasureSpec);        int width = 0;        int height = 0;        //记录每一行的高度和宽度        int lineWidth = getPaddingLeft();        int lineHeight = getPaddingBottom();        int childCount = getChildCount();        for (int i = 0; i < childCount; i++) {            View child = getChildAt(i);            //测量子View的宽和高            measureChild(child, widthMeasureSpec, heightMeasureSpec);            MarginLayoutParams params = (MarginLayoutParams) child.getLayoutParams();            //子View占据的宽度            int childWidth = child.getMeasuredWidth() + params.leftMargin + params.rightMargin;            //子View占据的高度            int childHeight = child.getMeasuredHeight() + params.topMargin + params.bottomMargin;            if (lineWidth + childWidth < sizeWidth - getPaddingLeft() - getPaddingRight()) {  //未换行                //叠加行宽                lineWidth += childWidth;                //得到当前行的最大高度(同一行中所有子View中的最大高度)                lineHeight = Math.max(lineHeight, childHeight);            } else {   //换行                /**                 * 换行之后,改行的宽和高就能确定                 */                //对比得到最大的宽度(所有行中的最大行宽)                width = Math.max(width, lineWidth);                //记录高度                height += lineHeight;                //重置lineWidth和lineHeight                lineWidth = childWidth;                lineHeight = childHeight;            }            //最后一个控件            if (i == childCount - 1) {                width = Math.max(width, lineWidth);                height += lineHeight;            }        }        setMeasuredDimension(modeWidth == MeasureSpec.EXACTLY ? sizeWidth : width + getPaddingLeft() + getPaddingRight(),                             modeHeight == MeasureSpec.EXACTLY ? sizeHeight : height + getPaddingTop() + getPaddingBottom());    }    /**     * 存储每一行所有子View的集合     */    private List<List<View>> mAllView = new ArrayList<>();    /**     * 每一行的高度     */    private List<Integer> mLineHeight = new ArrayList<>();    @Override    protected void onLayout(boolean changed, int l, int t, int r, int b) {        mAllView.clear();        mLineHeight.clear();        //当前ViewGroup的宽度        int width = getWidth();        int lineWidth = 0;        int lineHeight = 0;        //存储每一行的所有子View        List<View> lineView = new ArrayList<>();        int childCount = getChildCount();        for (int i = 0; i < childCount; i++) {            View child = getChildAt(i);            MarginLayoutParams params = (MarginLayoutParams) child.getLayoutParams();            int childWidth = child.getMeasuredWidth() + params.leftMargin + params.rightMargin;            int childHeight = child.getMeasuredHeight() + params.topMargin + params.bottomMargin;            if (lineWidth + childWidth > width - getPaddingLeft() - getPaddingRight()) {                //记录LineHeight                mLineHeight.add(lineHeight);                //记录当前行的View                mAllView.add(lineView);                //重置行宽和行高                lineWidth = 0;                lineHeight = childHeight;                //重置子View集合                lineView = new ArrayList<>();            }            lineWidth += childWidth;            lineHeight = Math.max(lineHeight, childHeight);            lineView.add(child);        }        //最后一行        mLineHeight.add(lineHeight);        mAllView.add(lineView);        //设置子View的位置        int left = getPaddingLeft();        int top = getPaddingTop();        //行数        int lineCount = mAllView.size();        for (int i = 0; i < lineCount; i++) {            //当前行的所有子View的集合            lineView = mAllView.get(i);            lineHeight = mLineHeight.get(i);            for (int j = 0; j < lineView.size(); j++) {                View child = lineView.get(j);                if (child.getVisibility() == View.GONE) {                    continue;                }                MarginLayoutParams params = (MarginLayoutParams) child.getLayoutParams();                int childWidth = child.getMeasuredWidth() + params.leftMargin + params.rightMargin;                int childLeft = left + params.leftMargin;                int childTop = top + params.topMargin;                int childRight = childLeft + child.getMeasuredWidth();                int childBottom = childTop + child.getMeasuredHeight();                //为子View设置布局                child.layout(childLeft, childTop, childRight, childBottom);                //同一行所有子View高度相同,左边距叠加                left += childWidth;            }            left = getPaddingLeft();            top += lineHeight;        }    }    /**     * 与当前ViewGroup对应的LayoutParams     */    @Override    public LayoutParams generateLayoutParams(AttributeSet attrs) {        return new MarginLayoutParams(getContext(), attrs);    }}

MainActivity.java

package com.jackie.neteasenews;import android.os.Bundle;import android.support.v4.app.Fragment;import android.support.v4.app.FragmentActivity;import android.support.v4.view.ViewPager;import android.view.LayoutInflater;import android.view.View;import android.widget.ImageButton;import android.widget.PopupWindow;import android.widget.TextView;import com.viewpagerindicator.TabPageIndicator;import java.util.ArrayList;import java.util.List;public class MainActivity extends FragmentActivity {    private TabPageIndicator mTabPageIndicator;    private ViewPager mViewPager;    private ViewPagerIndicatorAdapter mAdapter;    private ImageButton mArrowButton;    private LayoutInflater mInflater;    private View mIndicatorView;    private IndicatorPopupWindow mIndicatorPopupWindow;    private FlowLayout mCurrentFlowLayout;    private FlowLayout mAllFlowLayout;    private HeadlineFragment mHeadlineFragment;    private EnjoyFragment mEnjoyFragment;    private HotspotFragment mHotspotFragment;    private SportFragment mSportFragment;    private HouseFragment mHouseFragment;    private NBAFragment mNBAFragment;    private CBAFragment mCBAFragment;    private MoreFragment mMoreFragment;    private List<Fragment> mFragmentList;    private List<TextView> mCurrentItemList;    private List<TextView> mAllItemList;    private static final String[] INDICATOR_CURRENT_ITEM = new String[] { "头条", "娱乐", "热点", "体育", "房产", "NBA", "CBA" };    private static final String[] INDICATOR_ALL_ITEM = { "杭州", "财经", "科技", "跟帖", "直播", "时尚", "轻松一刻", "汽车", "段子", "军事",                                                         "历史", "家居", "原创", "游戏", "健康", "政务", "漫画", "哒哒","彩票", "手机",                                                         "移动互联", "中国足球", "社会", "影视", "国际足球", "跑步", "数码", "云课堂", "旅游", "读书",                                                         "酒香", "教育", "亲子", "暴雪游戏", "情感", "艺术", "值得买", "图片", "博客", "论坛", "订阅" };    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        initView();        initData();        data2View();        initEvent();    }    private void initView() {        mInflater = LayoutInflater.from(this);        mTabPageIndicator = (TabPageIndicator) findViewById(R.id.indicator);        mViewPager = (ViewPager) findViewById(R.id.viewpager);        mArrowButton = (ImageButton) findViewById(R.id.indicator_arrow) ;        mIndicatorView = mInflater.inflate(R.layout.activity_indicator, null);        mIndicatorPopupWindow = new IndicatorPopupWindow(this, mIndicatorView);        mCurrentFlowLayout = (FlowLayout) mIndicatorView.findViewById(R.id.current_flow_layout);        mAllFlowLayout = (FlowLayout) mIndicatorView.findViewById(R.id.all_flow_layout);    }    private void initData() {        mHeadlineFragment = new HeadlineFragment();        mEnjoyFragment = new EnjoyFragment();        mHotspotFragment = new HotspotFragment();        mSportFragment = new SportFragment();        mHouseFragment = new HouseFragment();        mNBAFragment = new NBAFragment();        mCBAFragment = new CBAFragment();        mFragmentList = new ArrayList<>();        mFragmentList.add(mHeadlineFragment);        mFragmentList.add(mEnjoyFragment);        mFragmentList.add(mHotspotFragment);        mFragmentList.add(mSportFragment);        mFragmentList.add(mHouseFragment);        mFragmentList.add(mNBAFragment);        mFragmentList.add(mCBAFragment);        mCurrentItemList = new ArrayList<>();        mAllItemList = new ArrayList<>();        //初始化当前条目        for (int i = 0; i < INDICATOR_CURRENT_ITEM.length; i++) {            TextView textView = (TextView) mInflater.inflate(R.layout.indicator_item_textview, mCurrentFlowLayout, false);            textView.setText(INDICATOR_CURRENT_ITEM[i]);            mCurrentItemList.add(textView);            mCurrentFlowLayout.addView(textView);        }        //初始化候选条目        for (int i = 0; i < INDICATOR_ALL_ITEM.length; i++) {            TextView textView = (TextView) mInflater.inflate(R.layout.indicator_item_textview, mAllFlowLayout, false);            textView.setText(INDICATOR_ALL_ITEM[i]);            mAllItemList.add(textView);            mAllFlowLayout.addView(textView);        }    }    private void data2View() {        mAdapter = new ViewPagerIndicatorAdapter(getSupportFragmentManager(), mFragmentList, mCurrentItemList);        mViewPager.setAdapter(mAdapter);        //实例化ViewPagerIndicatorAdapter然后设置ViewPager与之关联        mTabPageIndicator.setViewPager(mViewPager, 0);    }    private void initEvent() {        mArrowButton.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                mArrowButton.setBackgroundResource(R.drawable.arrow_up);                //弹出                mIndicatorPopupWindow.setAnimationStyle(R.style.popup_window_anim);                mIndicatorPopupWindow.showAsDropDown(mArrowButton, 0, mTabPageIndicator.getHeight() / 2 - mArrowButton.getHeight());            }        });        mIndicatorPopupWindow.setOnDismissListener(new PopupWindow.OnDismissListener() {            @Override            public void onDismiss() {                mArrowButton.setBackgroundResource(R.drawable.arrow_down);            }        });        //更新指示器,会调用getPageTitle方法        mTabPageIndicator.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {            @Override            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {            }            @Override            public void onPageSelected(int position) {                mTabPageIndicator.notifyDataSetChanged();            }            @Override            public void onPageScrollStateChanged(int state) {            }        });        for (int i = 0; i < mCurrentItemList.size(); i++) {            final int position = i;            final TextView textView = mCurrentItemList.get(i);            textView.setOnClickListener(new View.OnClickListener() {                @Override                public void onClick(View v) {                    mIndicatorPopupWindow.dismiss();                    //直接显示                    mTabPageIndicator.setViewPager(mViewPager, mCurrentItemList.indexOf(textView));                }            });            //长按删除事件            textView.setOnLongClickListener(new View.OnLongClickListener() {                @Override                public boolean onLongClick(View v) {                    mFragmentList.remove(position);                    mCurrentItemList.remove(position);                    mCurrentFlowLayout.removeView(textView);                    mAdapter.notifyDataSetChanged();                    //更新指示器                    mTabPageIndicator.notifyDataSetChanged();                    mAllItemList.add(textView);                    mAllFlowLayout.addView(textView);                    //先将textView的长按事件移除,然后再重新初始化所有的点击事件                    textView.setLongClickable(false);                    initEvent();                    return true;                }            });        }        for (int i = 0; i < mAllItemList.size(); i++) {            final TextView textView = mAllItemList.get(i);            textView.setOnClickListener(new View.OnClickListener() {                @Override                public void onClick(View v) {                    //添加新的Fragment                    mMoreFragment = new MoreFragment(textView.getText().toString());                    mFragmentList.add(mMoreFragment);                    //添加相应的标题                    mCurrentItemList.add(textView);                    //通知适配器数据更新                    mAdapter.notifyDataSetChanged();                    mAllItemList.remove(textView);                    mAllFlowLayout.removeView(textView);                    mCurrentFlowLayout.addView(textView);                    //重新初始化点击事件                    /**                     * 从mAllItemList中移除一个元素添加到mCurrentItemList中                     * 先将textView在mAllItemList的点击事件清除掉,然后再重新初始化所有的点击事件                     * 否则,移除的元素的点击事件还是在mAllItemList中响应                     */                    textView.setClickable(false);                    initEvent();                }            });        }    }}

效果图如下:

附上源码:

https://github.com/shineflower/NeteaseNews.git

更多相关文章

  1. Android(安卓)中如何处理双击事件
  2. cocos2dx android平台事件系统解析
  3. Android百分比布局(PercentRelativeLayout)嵌套NavigationView自
  4. Android-防止事件导致的oncreate的多次调用
  5. android中获取文字的宽度
  6. Android(安卓)UI架构(四)--SurfaceFlinger的初始化.md
  7. Android输入法之输入系统
  8. Android百分比布局
  9. Android(安卓)View绘制过程以及事件传递原理

随机推荐

  1. 高效地获取XMLhttp对象
  2. 高性能JavaScript代码高亮插件
  3. js“DOM事件”之鼠标事件、js的测试方法
  4. 如何禁用IE和Firefox中的后退按钮? [重复]
  5. ASP.NET文本框不会失去焦点
  6. 如何制作可折叠的bootstrap导航栏?
  7. JavaScript基础练习(一)
  8. 未为添加到dom的行选择所有复选框列
  9. 使用没有后端脚本的Angularjs上传文件(例
  10. 最大调用堆栈大小超过了堆- redux