承接上一篇文章: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
标签:int,private,高仿,import,new,Android,客户端,textView,View From: https://blog.51cto.com/u_11407799/5914564