首页 > 其他分享 >Android高仿网易新闻客户端之动态添加标签

Android高仿网易新闻客户端之动态添加标签

时间:2022-12-06 10:06:29浏览次数:57  
标签:int private 高仿 import new Android 客户端 textView View


承接上一篇文章:​​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();
}
});
}
}
}


效果图如下:

Android高仿网易新闻客户端之动态添加标签_ide

附上源码:

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

标签:int,private,高仿,import,new,Android,客户端,textView,View
From: https://blog.51cto.com/u_11407799/5914564

相关文章

  • Android 自定义组件之如何实现自定义组件
    简介Android提供了用于构建UI的强大的组件模型。两个基类:View和ViewGroup。可用Widget的部分名单包括Button,TextView,EditText,ListView,CheckBox,RadioButton,Gallery,Spin......
  • Android高仿京东、天猫下拉刷新
    说到下拉刷新,相信大家都不陌生,现在基本上每个项目都会用到。我们公司的项目一直都是使用SwipeRefreshLayout,官方的MaterialDesign风格,好用少Bug。现在下拉刷新大概有下面几......
  • Android开源框架Universal-Image-Loader基本介绍和使用
    相信大家平时做Android应用的时候,多少会接触到异步加载图片,或者加载大量图片的问题,这个开源框架就是用来做这些工作的。该项目存在于Github上面​​https://github.com/nost......
  • Android集成友盟推送功能
    友盟是中国最大的移动开发者服务平台,为移动开发者提供免费的应用统计分析、社交分享、消息推送、自动更新、在线参数、移动推广效果分析、微社区等app开发和运营解决方案。......
  • Android PullToRefresh上拉和下拉刷新
    Github链接:​​https://github.com/chrisbanes/Android-PullToRefresh​​GUIDE:​​https://github.com/chrisbanes/Android-PullToRefresh/wiki/Quick-Start-Guide​​1.......
  • Android Widget 小部件(二) 使用configure
    在添加Widget之前需要做一些处理操作,可以使用 配置活动在​​上一篇​​的实现基础上,加上配置活动(configure=activity)。这时添加Widget时,会先打开一个Activity,进行配置操......
  • Android高仿网易新闻客户端之首页
    关于实现网易新闻客户端的界面,以前写过很多博客,请参考:​​Android实现网易新闻客户端效果​​​​Android实现网易新闻客户端侧滑菜单(一)​​​​Android实现网易新闻客户端......
  • Android高仿网易新闻客户端之侧滑菜单
    承接上一篇文章:​​Android高仿网易新闻客户端之动态添加标签​​,今天实现侧滑菜单的效果。关于侧滑菜单,有很多种实现方式:1.自定义ViewGroup请参考:​​Android实现网易新......
  • Android 自定义标题栏Title Bar
    在Android自定义标题栏,步骤很简单:1.在onCreate方法中声明如下代码:requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);setContentView(R.id.activity_main);getWindow().......
  • 获取客户端信息测试
    MicrosoftWindows[版本10.0.19044.1766](c)MicrosoftCorporation。保留所有权利。(env)E:\pyAPP\Madking>pipinstallWMICollectingWMIDownloadingWMI-1.5.1-p......