【GT-安卓应用开发之点赞列表实现】
前言:今天闲来无事想到了刚接触安卓不久的时候特别感兴趣的一个东西,那就是自定义View属性。恰巧今天闲来无事,就写一个简单的类似于朋友圈点赞列表的小程序。
我的思路是这样的:点赞列表采用流式布局,由于用户点击名字可以查看用户资料,所以我自定义一个TextView,并定义一个展示用的username和查询资料所需要的userid。
首先,实现自定义TextView:
1、定义自定义属性
在values目录下新建xml文件attrs.xml,添加代码
<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="MyTextView"> <attr name="username" format="string"/> <attr name="userid" format="integer"/> <attr name="style" format="string" > <flag name="styleA" value="0"/> <flag name="styleB" value="1"/> </attr> <attr name="check" format="string" > <flag name="checked" value="0"/> <flag name="unchecked" value="1"/> </attr> </declare-styleable> </resources>
2、创建MyTextView并继承TextView,实现构造函数和onDraw方法(onMeasure跟onLayout用不到就不需重写了)
public class MyTextView extends TextView{ private String username; private int userid = -1; private String style; private String checked; public MyTextView(Context context) { super(context); } public MyTextView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); TypedArray ta = getContext().obtainStyledAttributes(attrs, R.styleable.MyTextView); username = ta.getString(R.styleable.MyTextView_username); userid = ta.getInt(R.styleable.MyTextView_userid,-1); style = ta.getString(R.styleable.MyTextView_style); checked = ta.getString(R.styleable.MyTextView_check); Log.e("checked",checked+"s"); ta.recycle(); } public MyTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); TypedArray ta = getContext().obtainStyledAttributes(attrs, R.styleable.MyTextView); username = ta.getString(R.styleable.MyTextView_username); userid = ta.getInt(R.styleable.MyTextView_userid,-1); style = ta.getString(R.styleable.MyTextView_style); checked = ta.getString(R.styleable.MyTextView_check); ta.recycle(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if(style.equals("0x0")){ setText(username+","); }else{ setText(username); } if(checked.equals("0x0")){ setTextColor(Color.BLUE); }else{ setTextColor(Color.GRAY); } } public String getUserName(){ return username; } public int getUserId(){ return userid; } }
TextView创建完了,则创建流式布局(从网上找了一个直接套过来的)
public class MyFlowLayout extends ViewGroup { public MyFlowLayout(Context context) { this(context, null); } public MyFlowLayout(Context context, AttributeSet attrs) { this(context, attrs, 0); } public MyFlowLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } private List<List<View>> mLineViews = new ArrayList<List<View>>(); private List<Integer> mLineHeight = new ArrayList<Integer>(); /** * 测量所有子View大小,确定ViewGroup的宽高 * * @param widthMeasureSpec * @param heightMeasureSpec */ @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); //由于onMeasure会执行多次,避免重复的计算控件个数和高度,这里需要进行清空操作 mLineViews.clear(); mLineHeight.clear(); //获取测量的模式和尺寸大小 int widthMode = MeasureSpec.getMode(widthMeasureSpec); int widthSize = MeasureSpec.getSize(widthMeasureSpec)-getPaddingLeft()-getPaddingRight(); int heightMode = MeasureSpec.getMode(heightMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec)+getPaddingTop()+getPaddingBottom(); //记录ViewGroup真实的测量宽高 int viewGroupWidth = 0-getPaddingLeft()-getPaddingRight(); int viewGroupHeight = getPaddingTop()+getPaddingBottom(); if (widthMode == MeasureSpec.EXACTLY && heightMode == MeasureSpec.EXACTLY) { viewGroupWidth = widthSize; viewGroupHeight = heightSize; } else { //当前所占的宽高 int currentLineWidth = 0; int currentLineHeight = 0; //用来存储每一行上的子View List<View> lineView = new ArrayList<View>(); int childViewsCount = getChildCount(); for (int i = 0; i < childViewsCount; i++) { View childView = getChildAt(i); //对子View进行测量 measureChild(childView, widthMeasureSpec, heightMeasureSpec); MarginLayoutParams marginLayoutParams = (MarginLayoutParams) childView.getLayoutParams(); int childViewWidth = childView.getMeasuredWidth() + marginLayoutParams.leftMargin + marginLayoutParams.rightMargin; int childViewHeight = childView.getMeasuredHeight() + marginLayoutParams.topMargin + marginLayoutParams.bottomMargin; if (currentLineWidth + childViewWidth > widthSize) { //当前行宽+子View+左右外边距>ViewGroup的宽度,换行 viewGroupWidth = Math.max(currentLineWidth, widthSize); viewGroupHeight += currentLineHeight; //添加行高 mLineHeight.add(currentLineHeight); //添加行对象 mLineViews.add(lineView); //new新的一行 lineView = new ArrayList<View>(); //添加行对象里的子View lineView.add(childView); currentLineWidth = childViewWidth; } else { //当前行宽+子View+左右外边距<=ViewGroup的宽度,不换行 currentLineWidth += childViewWidth; currentLineHeight = Math.max(currentLineHeight, childViewHeight); //添加行对象里的子View lineView.add(childView); } if (i == childViewsCount - 1) { //最后一个子View的时候 //添加行对象 mLineViews.add(lineView); viewGroupWidth = Math.max(childViewWidth, viewGroupWidth); viewGroupHeight += childViewHeight; //添加行高 mLineHeight.add(currentLineHeight); } } } setMeasuredDimension(viewGroupWidth, viewGroupHeight); } /** * 设置ViewGroup里子View的具体位置 * * @param changed * @param l * @param t * @param r * @param b */ @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { int left = getPaddingLeft(); int top = getPaddingTop(); //一共有几行 int lines = mLineViews.size(); for (int i = 0; i < lines; i++) { //每行行高 int lineHeight = mLineHeight.get(i); //行内有几个子View List<View> viewList = mLineViews.get(i); int views = viewList.size(); for (int j = 0; j < views; j++) { View view = viewList.get(j); MarginLayoutParams marginLayoutParams = (MarginLayoutParams) view.getLayoutParams(); int vl = left + marginLayoutParams.leftMargin; int vt = top + marginLayoutParams.topMargin; int vr = vl + view.getMeasuredWidth(); int vb = vt + view.getMeasuredHeight(); view.layout(vl, vt, vr, vb); left += view.getMeasuredWidth() + marginLayoutParams.leftMargin + marginLayoutParams.rightMargin; } left = getPaddingLeft(); top += lineHeight; } } /** * 指定ViewGroup的LayoutParams * * @param attrs * @return */ @Override public LayoutParams generateLayoutParams(AttributeSet attrs) { return new MarginLayoutParams(getContext(), attrs); } }
接下来就是在流式布局中添加MyTextView,我这里是静态添加的,可以在JAVA代码中通过addView实现动态添加,代码如下:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#ffffff" android:orientation="vertical"> <com.example.administrator.testdemo.MyFlowLayout android:layout_width="match_parent" android:layout_height="wrap_content" > <TextView android:layout_width="match_parent" android:layout_height="4dp" /> <ImageView android:layout_width="20dp" android:layout_height="20dp" android:src="@drawable/dz1"/> <com.example.administrator.testdemo.MyTextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="10dp" app:username="KOBE BRYANT" app:userid="24" android:text="1234" app:style="styleA" app:check="checked" android:onClick="click" /> <com.example.administrator.testdemo.MyTextView android:layout_width="wrap_content" android:layout_height="wrap_content" app:username="LEBORN JAMES" app:userid="23" android:text="1234" app:style="styleA" app:check="checked" android:onClick="click" /> <com.example.administrator.testdemo.MyTextView android:layout_width="wrap_content" android:layout_height="wrap_content" app:username="ALLEN IVERSON" app:userid="3" android:text="1234" app:style="styleA" app:check="checked" android:onClick="click" /> <com.example.administrator.testdemo.MyTextView android:layout_width="wrap_content" android:layout_height="wrap_content" app:username="STEVE NASH" app:userid="10" android:text="1234" app:style="styleA" app:check="checked" android:onClick="click" /> <com.example.administrator.testdemo.MyTextView android:layout_width="wrap_content" android:layout_height="wrap_content" app:username="VINCE CATER" app:userid="15" android:text="1234" app:style="styleA" app:check="checked" android:onClick="click" /> <com.example.administrator.testdemo.MyTextView android:layout_width="wrap_content" android:layout_height="wrap_content" app:username="TRACY MCGRADY" app:userid="1" android:text="1234" app:style="styleA" app:check="checked" android:onClick="click" /> <com.example.administrator.testdemo.MyTextView android:layout_width="wrap_content" android:layout_height="wrap_content" app:username="DWGHIT HOWARD" app:userid="12" android:text="1234" app:style="styleA" app:check="checked" android:onClick="click" /> <com.example.administrator.testdemo.MyTextView android:layout_width="wrap_content" android:layout_height="wrap_content" app:username="KEVIN GANNET" app:userid="21" android:text="1234" app:style="styleA" app:check="checked" android:onClick="click" /> <com.example.administrator.testdemo.MyTextView android:layout_width="wrap_content" android:layout_height="wrap_content" app:username="PAUL GASOL" app:userid="16" android:text="1234" app:style="styleB" app:check="checked" android:onClick="click" /> </com.example.administrator.testdemo.MyFlowLayout> </LinearLayout>
最后就是事件的处理,在这个程序中只是点击显示username和userid,代码很简单
public void click(View view) { MyTextView mView = (MyTextView) view; Toast.makeText(MainActivity.this,mView.getUserName()+","+mView.getUserId(),Toast.LENGTH_SHORT).show(); }
效果图: