亦余心之所善兮,虽九死其犹未悔。这篇文章主要讲述android 自己定义ViewGroup实现可记载并呈现选择的ListView相关的知识,希望能为你提供帮助。
转载请注明出处:王亟亟的大牛之路
之前也做过一些用TextView之类的记录ListView选项的东西。可是总认为好难看。发现个不错的实现就贴给大家。
项目文件夹
文章图片
执行效果:
文章图片
【android 自己定义ViewGroup实现可记载并呈现选择的ListView】自己定义视图:
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
public class FlowLayout extends ViewGroup {private int mGravity = (isIcs() ? Gravity.START : Gravity.LEFT) | Gravity.TOP;
private final List<
List<
View>
>
mLines = new ArrayList<
List<
View>
>
();
private final List<
Integer>
mLineHeights = new ArrayList<
Integer>
();
private final List<
Integer>
mLineMargins = new ArrayList<
Integer>
();
public FlowLayout(Context context) {
this(context, null);
}public FlowLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}public FlowLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.FlowLayout, defStyle, 0);
try {
int index = a.getInt(R.styleable.FlowLayout_android_gravity, -1);
if(index >
0) {
setGravity(index);
}
} finally {
a.recycle();
}}/**
* {@inheritDoc}
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int sizeWidth = MeasureSpec.getSize(widthMeasureSpec) - getPaddingLeft() - getPaddingRight();
int sizeHeight = MeasureSpec.getSize(heightMeasureSpec);
int modeWidth = MeasureSpec.getMode(widthMeasureSpec);
int modeHeight = MeasureSpec.getMode(heightMeasureSpec);
int width = 0;
int height = getPaddingTop() + getPaddingBottom();
int lineWidth = 0;
int lineHeight = 0;
int childCount = getChildCount();
for(int i = 0;
i <
childCount;
i++) {View child = getChildAt(i);
boolean lastChild = i == childCount - 1;
if(child.getVisibility() == View.GONE) {if(lastChild) {
width = Math.max(width, lineWidth);
height += lineHeight;
}continue;
}measureChildWithMargins(child, widthMeasureSpec, lineWidth, heightMeasureSpec, height);
LayoutParams lp = (LayoutParams) child.getLayoutParams();
int childWidthMode = MeasureSpec.AT_MOST;
int childWidthSize = sizeWidth;
int childHeightMode = MeasureSpec.AT_MOST;
int childHeightSize = sizeHeight;
if(lp.width == LayoutParams.MATCH_PARENT) {
childWidthMode = MeasureSpec.EXACTLY;
childWidthSize -= lp.leftMargin + lp.rightMargin;
} else if(lp.width >
= 0) {
childWidthMode = MeasureSpec.EXACTLY;
childWidthSize = lp.width;
}if(lp.height >
= 0) {
childHeightMode = MeasureSpec.EXACTLY;
childHeightSize = lp.height;
} else if (modeHeight == MeasureSpec.UNSPECIFIED) {
childHeightMode = MeasureSpec.UNSPECIFIED;
childHeightSize = 0;
}child.measure(
MeasureSpec.makeMeasureSpec(childWidthSize, childWidthMode),
MeasureSpec.makeMeasureSpec(childHeightSize, childHeightMode)
);
int childWidth = child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin;
if(lineWidth + childWidth >
sizeWidth) {width = Math.max(width, lineWidth);
lineWidth = childWidth;
height += lineHeight;
lineHeight = child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin;
} else {
lineWidth += childWidth;
lineHeight = Math.max(lineHeight, child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin);
}if(lastChild) {
width = Math.max(width, lineWidth);
height += lineHeight;
}}width += getPaddingLeft() + getPaddingRight();
setMeasuredDimension(
(modeWidth == MeasureSpec.EXACTLY) ? sizeWidth : width,
(modeHeight == MeasureSpec.EXACTLY) ? sizeHeight : height);
}/**
* {@inheritDoc}
*/
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {mLines.clear();
mLineHeights.clear();
mLineMargins.clear();
int width = getWidth();
int height = getHeight();
int linesSum = getPaddingTop();
int lineWidth = 0;
int lineHeight = 0;
List<
View>
lineViews = new ArrayList<
View>
();
float horizontalGravityFactor;
switch ((mGravity &
Gravity.HORIZONTAL_GRAVITY_MASK)) {
case Gravity.LEFT:
default:
horizontalGravityFactor = 0;
break;
case Gravity.CENTER_HORIZONTAL:
horizontalGravityFactor = .5f;
break;
case Gravity.RIGHT:
horizontalGravityFactor = 1;
break;
}for(int i = 0;
i <
getChildCount();
i++) {View child = getChildAt(i);
if(child.getVisibility() == View.GONE) {
continue;
}LayoutParams lp = (LayoutParams) child.getLayoutParams();
int childWidth = child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin;
int childHeight = child.getMeasuredHeight() + lp.bottomMargin + lp.topMargin;
if(lineWidth + childWidth >
width) {
mLineHeights.add(lineHeight);
mLines.add(lineViews);
mLineMargins.add((int) ((width - lineWidth) * horizontalGravityFactor) + getPaddingLeft());
linesSum += lineHeight;
lineHeight = 0;
lineWidth = 0;
lineViews = new ArrayList<
View>
();
}lineWidth += childWidth;
lineHeight = Math.max(lineHeight, childHeight);
lineViews.add(child);
}mLineHeights.add(lineHeight);
mLines.add(lineViews);
mLineMargins.add((int) ((width - lineWidth) * horizontalGravityFactor) + getPaddingLeft());
linesSum += lineHeight;
int verticalGravityMargin = 0;
switch ((mGravity &
Gravity.VERTICAL_GRAVITY_MASK)) {
case Gravity.TOP:
default:
break;
case Gravity.CENTER_VERTICAL:
verticalGravityMargin = (height - linesSum) / 2;
break;
case Gravity.BOTTOM:
verticalGravityMargin = height - linesSum;
break;
}int numLines = mLines.size();
int left;
int top = getPaddingTop();
for(int i = 0;
i <
numLines;
i++) {lineHeight = mLineHeights.get(i);
lineViews = mLines.get(i);
left = mLineMargins.get(i);
int children = lineViews.size();
for(int j = 0;
j <
children;
j++) {View child = lineViews.get(j);
if(child.getVisibility() == View.GONE) {
continue;
}LayoutParams lp = (LayoutParams) child.getLayoutParams();
// if height is match_parent we need to remeasure child to line height
if(lp.height == LayoutParams.MATCH_PARENT) {
int childWidthMode = MeasureSpec.AT_MOST;
int childWidthSize = lineWidth;
if(lp.width == LayoutParams.MATCH_PARENT) {
childWidthMode = MeasureSpec.EXACTLY;
} else if(lp.width >
= 0) {
childWidthMode = MeasureSpec.EXACTLY;
childWidthSize = lp.width;
}child.measure(
MeasureSpec.makeMeasureSpec(childWidthSize, childWidthMode),
MeasureSpec.makeMeasureSpec(lineHeight - lp.topMargin - lp.bottomMargin, MeasureSpec.EXACTLY)
);
}int childWidth = child.getMeasuredWidth();
int childHeight = child.getMeasuredHeight();
int gravityMargin = 0;
if(Gravity.isVertical(lp.gravity)) {
switch (lp.gravity) {
case Gravity.TOP:
default:
break;
case Gravity.CENTER_VERTICAL:
case Gravity.CENTER:
gravityMargin = (lineHeight - childHeight - lp.topMargin - lp.bottomMargin) / 2 ;
break;
case Gravity.BOTTOM:
gravityMargin = lineHeight - childHeight - lp.topMargin - lp.bottomMargin;
break;
}
}child.layout(left + lp.leftMargin,
top + lp.topMargin + gravityMargin + verticalGravityMargin,
left + childWidth + lp.leftMargin,
top + childHeight + lp.topMargin + gravityMargin + verticalGravityMargin);
left += childWidth + lp.leftMargin + lp.rightMargin;
}top += lineHeight;
}}@Override
protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
return new LayoutParams(p);
}/**
* {@inheritDoc}
*/
@Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
return new LayoutParams(getContext(), attrs);
}/**
* {@inheritDoc}
*/
@Override
protected LayoutParams generateDefaultLayoutParams() {
return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
}@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
public void setGravity(int gravity) {
if(mGravity != gravity) {
if((gravity &
Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) == 0) {
gravity |= isIcs() ? Gravity.START : Gravity.LEFT;
}if((gravity &
Gravity.VERTICAL_GRAVITY_MASK) == 0) {
gravity |= Gravity.TOP;
}mGravity = gravity;
requestLayout();
}
}public int getGravity() {
return mGravity;
}/**
* @return <
code>
true<
/code>
if device is running ICS or grater version of Android.
*/
private static boolean isIcs() {
return Build.VERSION.SDK_INT >
= Build.VERSION_CODES.ICE_CREAM_SANDWICH;
}public static class LayoutParams extends MarginLayoutParams {public int gravity = -1;
public LayoutParams(Context c, AttributeSet attrs) {
super(c, attrs);
TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.FlowLayout_Layout);
try {
gravity = a.getInt(R.styleable.FlowLayout_Layout_android_layout_gravity, -1);
} finally {
a.recycle();
}
}public LayoutParams(int width, int height) {
super(width, height);
}public LayoutParams(ViewGroup.LayoutParams source) {
super(source);
}}}
分析:这部分主要是呈现被选项的实现。伸手党能够无视
对象:
public class Filter_Object {
public String mName ;
public boolean mIsSelected ;
}
分析:填充是否被选,以及listView每一行的显示内容
MainActivity:
public class MainActivity extends AppCompatActivity {
private ListView mListView;
private ArrayList<
Filter_Object>
mArrFilter;
private ScrollView mScrollViewFilter;
private Filter_Adapter mFilter_Adapter ;
private FlowLayout mFlowLayoutFilter ;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (Build.VERSION.SDK_INT >
= Build.VERSION_CODES.LOLLIPOP) {getWindow().setStatusBarColor(getResources().getColor(R.color.themecolor));
}mArrFilter = new ArrayList<
>
();
String[] strArr = getResources().getStringArray(R.array.city);
int lengthOfstrArr = strArr.length;
for (int i = 0;
i <
lengthOfstrArr;
i++) {
Filter_Object filter_object = new Filter_Object();
filter_object.mName = strArr[i];
filter_object.mIsSelected = false;
mArrFilter.add(filter_object);
}getSupportActionBar().setDisplayShowTitleEnabled(true);
getSupportActionBar().setTitle(getString(R.string.app_name));
mListView = (ListView) findViewById(R.id.listViewFilter);
mScrollViewFilter = (ScrollView)findViewById(R.id.scrollViewFilter);
//放置被选项的布局
mFlowLayoutFilter = (FlowLayout)findViewById(R.id.flowLayout);
mFilter_Adapter = new Filter_Adapter(mArrFilter);
mListView.setAdapter(mFilter_Adapter);
}
public void addFilterTag() {
final ArrayList<
Filter_Object>
arrFilterSelected = new ArrayList<
>
();
mFlowLayoutFilter.removeAllViews();
int length = mArrFilter.size();
boolean isSelected = false;
for (int i = 0;
i <
length;
i++) {
Filter_Object fil = mArrFilter.get(i);
if (fil.mIsSelected) {
isSelected = true;
arrFilterSelected.add(fil);
}
}
if (isSelected) {
mScrollViewFilter.setVisibility(View.VISIBLE);
} else {
mScrollViewFilter.setVisibility(View.GONE);
}
int size = arrFilterSelected.size();
LayoutInflater layoutInflater = (LayoutInflater)
this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
for (int i = 0;
i <
size;
i++) {
View view = layoutInflater.inflate(R.layout.filter_tag_edit, null);
TextView tv = (TextView) view.findViewById(R.id.tvTag);
LinearLayout linClose = (LinearLayout) view.findViewById(R.id.linClose);
final Filter_Object filter_object = arrFilterSelected.get(i);
linClose.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//showToast(filter_object.name);
int innerSize = mArrFilter.size();
for (int j = 0;
j <
innerSize;
j++) {
Filter_Object mFilter_Object = mArrFilter.get(j);
if (mFilter_Object.mName.equalsIgnoreCase(filter_object.mName)) {
mFilter_Object.mIsSelected = false;
}
}
addFilterTag();
mFilter_Adapter.updateListView(mArrFilter);
}
});
tv.setText(filter_object.mName);
int color = getResources().getColor(R.color.themecolor);
View newView = view;
newView.setBackgroundColor(color);
FlowLayout.LayoutParams params = new FlowLayout.LayoutParams(FlowLayout.LayoutParams.WRAP_CONTENT, FlowLayout.LayoutParams.WRAP_CONTENT);
params.rightMargin = 10;
params.topMargin = 5;
params.leftMargin = 10;
params.bottomMargin = 5;
newView.setLayoutParams(params);
mFlowLayoutFilter.addView(newView);
}
}public class Filter_Adapter extends BaseAdapter {
ArrayList<
Filter_Object>
arrMenu;
public Filter_Adapter(ArrayList<
Filter_Object>
arrOptions) {
this.arrMenu = arrOptions;
}public void updateListView(ArrayList<
Filter_Object>
mArray) {
this.arrMenu = mArray;
notifyDataSetChanged();
}@Override
public int getCount() {
return this.arrMenu.size();
}@Override
public Object getItem(int position) {
return null;
}@Override
public long getItemId(int position) {
return 0;
}@Override
public View getView(final int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder;
if (convertView == null) {
convertView = getLayoutInflater().inflate(R.layout.filter_list_item, null);
viewHolder = new ViewHolder();
viewHolder.mTtvName = (TextView) convertView.findViewById(R.id.tvName);
viewHolder.mTvSelected = (TextView) convertView.findViewById(R.id.tvSelected);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
final Filter_Object mService_Object = arrMenu.get(position);
viewHolder.mTtvName.setText(mService_Object.mName);
if (mService_Object.mIsSelected) {
viewHolder.mTvSelected.setVisibility(View.VISIBLE);
} else {
viewHolder.mTvSelected.setVisibility(View.INVISIBLE);
}
convertView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {mService_Object.mIsSelected = !mService_Object.mIsSelected;
mScrollViewFilter.setVisibility(View.VISIBLE);
addFilterTag();
notifyDataSetChanged();
}
});
return convertView;
}public class ViewHolder {
TextView mTtvName, mTvSelected;
}
}@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu;
this adds items to the action bar if it is present.
// getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}return super.onOptionsItemSelected(item);
}
}
分析:层次非常分明,从填充本地数据–> 转加载ListView–> 附加逻辑–> 呈现。等流程思路非常清晰,可读性非常强。
详细使用,能够看源代码。一目了然。
源代码地址:http://yunpan.cn/cdbbFUd8rLFmJ訪问password af07
推荐阅读
- android:怎样用一天时间,写出“飞机大战”这种游戏!(无框架-SurfaceView绘制)
- 安卓下载文件怎样更新UI进度
- Android之TextureView浅析
- Android studio启动后卡在refreshing gradle project(包解决)
- android模拟器不能上网设置
- Android小经验
- AndroidManifest.xml里加入不同package的component (ActivityService里android:name里指定的值一般为句号加类名),可以通过指定完全类名(包名
- Android 4.4.2 动态加入JNI库方法记录 (二 app应用层)
- Android清单文件具体解释 ---- backupAgent的使用方法