Android通用索引欄實現

偶爾看到之前寫過的代碼,感覺好多東西幾乎在很多項目中都要用到,雖然每個項目的需求和設計都不同,不過實現的效果都是一樣的,可能只是數據格式和一些顏色等的細微差距.但是有的時候因爲一個小改變,就要去重複的修改代碼,麻煩不說,也容易導致新的問題和BUG.

就拿忽然想到的索引欄來說,幾乎寫過的項目中都用到了,比如城市選擇、聯繫人等等.這些地方全都需要用到索引欄,但是用法都是一樣的.翻看了幾處之前寫過的代碼,發現每次用到索引欄,都要重新去寫方法來處理數據或者對數據的索引進行提取這些,做法也都大同小異.於是乎,嘗試着重構一下這部分,也方便之後的使用.

先看一下效果圖:

這裏寫圖片描述


實現

索引欄的實現,網上有很多例子,也比較簡單,就不做過多解釋.因爲在不同項目中可能涉及到索引欄字體顏色、大小不同等問題,所以把之前用到的代碼做一下修改,提取出一些自定義屬性,方便修改,就不必每次都去代碼中修改,也避免影響到其他人的使用.直接看一下代碼,在attr中定義一些自定義屬性,如下:

attr:

 <?xml version="1.0" encoding="utf-8"?>
<resources>
    <!--SideBar相關-->
    <!--普通時的顏色-->
    <attr name="normalColor" format="color"/>
    <!--選中時的顏色-->
    <attr name="chooseColor" format="color"/>
    <!--普通時的背景圖-->
    <attr name="normalBackground" format="reference"/>
    <!--選中時的背景圖-->
    <attr name="chooseBackground" format="reference"/>
    <!--索引欄文字大小-->
    <attr name="sideTextSize" format="dimension"/>
    <declare-styleable name="SideBar">
        <attr name="normalColor"/>
        <attr name="chooseColor"/>
        <attr name="normalBackground"/>
        <attr name="chooseBackground"/>
        <attr name="sideTextSize"/>
    </declare-styleable>
</resources>

把顏色文字大小等屬性提取出來方便修改.然後看一下SideBar

SideBar:

package com.example.junweiliu.commindexdemo.widget;


import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;
import android.widget.TextView;

import com.example.junweiliu.commindexdemo.R;


/**
 * Created by junweiliu on 16/11/24.
 */
public class SideBar extends View {
    /**
     * 點擊回調
     */
    private OnTouchingLetterChangedListener onTouchingLetterChangedListener;
    /**
     * 26字母
     */
    public static String[] letterStrs = {"A", "B", "C", "D", "E", "F", "G", "H", "I",
            "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V",
            "W", "X", "Y", "Z", "#"};
    /**
     * 當前是否選中
     */
    private int choose = -1;
    /**
     * 字母畫筆
     */
    private Paint paint = new Paint();
    /**
     * 顯示的TextView
     */
    private TextView mTextDialog;
    /**
     * 普通時的顏色
     */
    private int normalColor;
    /**
     * 選中的顏色
     */
    private int chooseColor;
    /**
     * 普通時的背景
     */
    private Drawable normalBackground;
    /**
     * 選中時的背景
     */
    private Drawable chooseBackground;
    /**
     * 文字大小
     */
    private float textSize;
    /**
     * 邊框
     */
    private Rect mRect;


    public SideBar(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public SideBar(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        // 獲取自定義屬性
        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.SideBar);
        normalColor = ta.getColor(R.styleable.SideBar_normalColor, Color.GRAY);
        chooseColor = ta.getColor(R.styleable.SideBar_chooseColor, Color.RED);
        normalBackground = ta.getDrawable(R.styleable.SideBar_normalBackground);
        chooseBackground = ta.getDrawable(R.styleable.SideBar_chooseBackground);
        textSize = ta.getDimension(R.styleable.SideBar_sideTextSize, TypedValue
                .applyDimension(TypedValue.COMPLEX_UNIT_SP, 13,
                        getResources().getDisplayMetrics()));
        ta.recycle();
        init();
    }

    /**
     * 爲SideBar設置顯示字母的TextView
     *
     * @param mTextDialog
     */
    public void setTextView(TextView mTextDialog) {
        this.mTextDialog = mTextDialog;
    }

    /**
     * 設置
     *
     * @param letter
     */
    public void setLetter(String[] letter) {
        this.letterStrs = letter;
        invalidate();
        requestLayout();
    }


    /**
     * 初始化參數
     */
    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
    private void init() {
        paint.setColor(normalColor);
        paint.setTypeface(Typeface.DEFAULT_BOLD);
        paint.setAntiAlias(true);
        paint.setTextSize(textSize);
        // 獲取單個繪製的rect,用於獲取單個繪製項的高度
        mRect = new Rect();
        paint.getTextBounds("A", 0, "A".length(), mRect);
    }


    /**
     * 繪製
     *
     * @param canvas
     */
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        // 獲取焦點改變背景顏色.
        int height = getHeight() - getPaddingTop() - getPaddingBottom();// 獲取對應高度
        int width = getWidth(); // 獲取對應寬度
        int singleHeight = height / letterStrs.length;// 獲取每一個字母的高度
        for (int i = 0; i < letterStrs.length; i++) {
            // 選中的狀態
            if (i == choose) {
                paint.setColor(chooseColor);
                paint.setFakeBoldText(true);
            }
            // x座標等於中間-字符串寬度的一半.
            float xPos = width / 2 - paint.measureText(letterStrs[i]) / 2;
            float yPos = singleHeight * i + singleHeight;
            canvas.drawText(letterStrs[i], xPos, yPos, paint);
            paint.reset();// 重置畫筆
            init();
        }
    }

    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        final int action = event.getAction();
        // 點擊的y座標
        final float y = event.getY();
        final int oldChoose = choose;
        final OnTouchingLetterChangedListener listener = onTouchingLetterChangedListener;
        // 獲取當前點擊的字母位置,點擊位置的y座標比上總的高度相當於點擊的位置比上全部位置(c / b.length = y / getHeight())
        final int currChoose = (int) (y / getHeight() * letterStrs.length);

        switch (action) {
            case MotionEvent.ACTION_UP:
                // 重置背景色
                if (null != normalBackground) {
                    setBackground(normalBackground);
                } else {
                    setBackgroundColor(Color.argb(0, 0, 0, 0));
                }
                // 擡起時置爲-1
                choose = -1;
                invalidate();
                if (mTextDialog != null) {
                    mTextDialog.setVisibility(View.INVISIBLE);
                }
                break;
            default:
                // 設置背景色
                if (null != chooseBackground) {
                    setBackground(chooseBackground);
                }
                if (oldChoose != currChoose) {
                    if (currChoose >= 0 && currChoose < letterStrs.length) {
                        if (null != listener) {
                            listener.onTouchingLetterChanged(letterStrs[currChoose]);
                        }
                        if (null != mTextDialog) {
                            mTextDialog.setText(letterStrs[currChoose]);
                            mTextDialog.setVisibility(View.VISIBLE);
                        }
                        // 設置選中的位置爲當前位置
                        choose = currChoose;
                        invalidate();
                    }
                }
                break;
        }
        return true;
    }

    /**
     * 向外公開的方法
     *
     * @param onTouchingLetterChangedListener
     */
    public void setOnTouchingLetterChangedListener(
            OnTouchingLetterChangedListener onTouchingLetterChangedListener) {
        this.onTouchingLetterChangedListener = onTouchingLetterChangedListener;
    }

    /**
     * 回調接口
     *
     * @author coder
     */
    public interface OnTouchingLetterChangedListener {
        void onTouchingLetterChanged(String s);
    }


    /**
     * 測量
     *
     * @param widthMeasureSpec
     * @param heightMeasureSpec
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int sizeWidth = MeasureSpec.getSize(widthMeasureSpec);
        int sizeHeight = MeasureSpec.getSize(heightMeasureSpec);
        // 當高度爲自適應時,高度爲字母高度*字母數量*2 即間隔爲單位高度
        int wrapHeight = letterStrs.length * (mRect.height() * 2);
        // 當寬度爲自適應使,寬度爲字母寬度*2
        int warpWidth = mRect.width() * 2;
        setMeasuredDimension((widthMode == MeasureSpec.EXACTLY) ? sizeWidth : warpWidth
                , (heightMode == MeasureSpec.EXACTLY) ? sizeHeight
                        //wrap_content時的高度
                        : wrapHeight);
    }

}

很簡單,只是提取出來了一些自定義屬性,沒什麼可說的,接下來分析一下如何讓索引欄變得通用,先來想一下索引欄一般的寫法.首先拿到一個數據源,然後對這個數據源進行處理,從數據源中提取出首字母當做索引(當然數據源中可能已經含有首字母或者索引等字段),有了索引之後,再在適配器中進行判斷來控制是否顯示索引標題(我的做法是判斷第一次出現當前索引的數據源位置和當前位置是否相同,如果相同則顯示索引標題),處理完索引標題的顯示和隱藏,最後就是跟索引欄進行綁定(實現索引欄的回調方法並做相關處理).大體步驟就是這樣,接下來就是找一下處理不同的地方,比對了一下,發現問題基本都是出現在數據格式不同上,有的數據的索引字段可能叫Letter,有的可能叫LetterName,這就導致了每次對這些數據進行處理時,都要重新寫方法或者修改方法,使得這些方法不共用.那怎麼解決一下這個問題呢,最開始想到的是寫一個抽象類,然後用一個抽象方法getLetterName()來約束索引.每個需要用到索引欄的Bean都去繼承這個抽象類,重寫這個抽象方法,從而達到統一約束索引值的效果,也就解決了索引值字段不同的問題,這樣就可以用一個公共的方法來處理不同的數據源.後來又考慮了一下,這個地方其實用接口會更加合適一點,接口靈活性更大,而且也是面向接口編程的一種體現.分析了這麼多,來具體代碼實現一下,提出一個接口,之後所有需要用到索引的數據Bean去實現這個接口中的getLetterName()方法並且重寫這個方法來返回索引值即可.

接口SideBase:

package com.example.junweiliu.commindexdemo.bean;

/**
 * Created by junweiliu on 16/11/21.
 */
public interface SideBase {
    String getLetterName();
}

然後數據Bean去實現這個接口,例如比較常見的CityBean:

package com.example.junweiliu.commindexdemo.bean;

public class CityBean implements SideBase {
    /**
     * 城市名
     */
    private String cityName;
    /**
     * 首字母
     */
    private String cityHeader;
    /**
     * 城市信息
     */
    private String cityMes;


    public CityBean(String cityName, String cityHeader, String cityMes) {
        this.cityName = cityName;
        this.cityHeader = cityHeader;
        this.cityMes = cityMes;
    }

    public String getCityName() {
        return cityName;
    }

    public void setCityName(String cityName) {
        this.cityName = cityName;
    }

    public String getCityHeader() {
        return cityHeader;
    }

    public void setCityHeader(String cityHeader) {
        this.cityHeader = cityHeader;
    }

    public String getCityMes() {
        return cityMes;
    }

    public void setCityMes(String cityMes) {
        this.cityMes = cityMes;
    }

    /**
     * 獲取索引
     *
     * @return
     */
    @Override
    public String getLetterName() {
        return cityHeader;
    }
}

在getLetterName()方法中去返回索引值.

接下來就可以去寫一些公共的處理方法.比如

    /**
     * 根據當前選中的項獲取其第一次出現該項首字母的位置
     *
     * @param position 當前選中的位置
     * @param datas    數據源
     * @return
     */
    public static int getPositionForSection(int position, List<? extends SideBase> datas) {
        // 當前選中的項
        SideBase sideBase = datas.get(position);
        for (int i = 0; i < datas.size(); i++) {
            String firstStr = datas.get(i).getLetterName().toUpperCase();
            // 返回第一次出現該項首字母的位置
            if (firstStr.equals(sideBase.getLetterName())) {
                return i;
            }
        }
        return -1;
    }

因爲使用的接口,這裏就可以用通配符?的方式來對數據進行處理,只關心和處理getLetterName()方法即可.還可以做其他處理:

    /**
     * 獲取所選中的索引在列表中的位置
     *
     * @param list
     * @param letter
     * @return
     */
    public static int getLetterPosition(List<? extends SideBase> list, String letter) {
        int position = -1;

        if (list != null && !list.isEmpty() && !"".equals(letter)) {
            for (int i = 0; i < list.size(); i++) {
                SideBase bean = list.get(i);
                if (bean.getLetterName().equals(letter)) {
                    position = i;
                    break;
                }
            }
        }
        return position;
    }

    /**
     * 篩選出數據源中所包含的全部索引值
     *
     * @param list
     * @return
     */
    public static String[] getLetters(List<? extends SideBase> list) {
        List<String> letters = new ArrayList<>();
        if (list != null && !list.isEmpty()) {
            for (int i = 0; i < list.size(); i++) {
                if (!letters.contains(list.get(i).getLetterName())) {
                    letters.add(list.get(i).getLetterName());
                }
            }
        }
        return (String[]) letters.toArray(new String[letters.size()]);
    }

通過分析和重構之後,這些之前不能公用的方法就變得通用起來,很方便,之後用起來也會特別簡單、舒心.


完整代碼

公共處理類

CommUtil:

package com.example.junweiliu.commindexdemo.util;

import com.example.junweiliu.commindexdemo.bean.SideBase;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by junweiliu on 16/11/24.
 */
public class CommUtil {

    /**
     * 根據當前選中的項獲取其第一次出現該項首字母的位置
     *
     * @param position 當前選中的位置
     * @param datas    數據源
     * @return
     */
    public static int getPositionForSection(int position, List<? extends SideBase> datas) {
        // 當前選中的項
        SideBase sideBase = datas.get(position);
        for (int i = 0; i < datas.size(); i++) {
            String firstStr = datas.get(i).getLetterName().toUpperCase();
            // 返回第一次出現該項首字母的位置
            if (firstStr.equals(sideBase.getLetterName())) {
                return i;
            }
        }
        return -1;
    }

    /**
     * 獲取所選中的索引在列表中的位置
     *
     * @param list
     * @param letter
     * @return
     */
    public static int getLetterPosition(List<? extends SideBase> list, String letter) {
        int position = -1;

        if (list != null && !list.isEmpty() && !"".equals(letter)) {
            for (int i = 0; i < list.size(); i++) {
                SideBase bean = list.get(i);
                if (bean.getLetterName().equals(letter)) {
                    position = i;
                    break;
                }
            }
        }
        return position;
    }

    /**
     * 篩選出數據源中所包含的全部索引值
     *
     * @param list
     * @return
     */
    public static String[] getLetters(List<? extends SideBase> list) {
        List<String> letters = new ArrayList<>();
        if (list != null && !list.isEmpty()) {
            for (int i = 0; i < list.size(); i++) {
                if (!letters.contains(list.get(i).getLetterName())) {
                    letters.add(list.get(i).getLetterName());
                }
            }
        }
        return (String[]) letters.toArray(new String[letters.size()]);
    }
}

適配器CityAdapter:

package com.example.junweiliu.commindexdemo.adapter;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;

import com.example.junweiliu.commindexdemo.R;
import com.example.junweiliu.commindexdemo.bean.CityBean;
import com.example.junweiliu.commindexdemo.util.CommUtil;

import java.util.List;

/**
 * Created by junweiliu on 16/11/24.
 */
public class CityAdapter extends BaseAdapter {
    /**
     * 上下文
     */
    private Context context;
    /**
     * 佈局加載器
     */
    private LayoutInflater mInflater;
    /**
     * 數據源
     */
    private List<CityBean> cityBeanList;

    /**
     * 構造方法
     *
     * @param context
     * @param cityBeanList
     */
    public CityAdapter(Context context, List<CityBean> cityBeanList) {
        this.context = context;
        this.cityBeanList = cityBeanList;
    }

    @Override
    public int getCount() {
        return cityBeanList.size();
    }

    @Override
    public Object getItem(int i) {
        return cityBeanList.get(i);
    }

    @Override
    public long getItemId(int i) {
        return i;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup viewGroup) {
        ViewHolder viewHolder = null;
        CityBean bean = cityBeanList.get(position);
        if (convertView == null) {
            convertView = mInflater.from(context).inflate(R.layout.item_city, null);
            viewHolder = new ViewHolder();
            viewHolder.headerTv = (TextView) convertView.findViewById(R.id.tv_item_citys_header);
            viewHolder.contentTv = (TextView) convertView.findViewById(R.id.tv_item_citys_context);
            convertView.setTag(viewHolder);
        } else {
            viewHolder = (ViewHolder) convertView.getTag();
        }
        // 如果當前位置爲第一次出現該類首字母的位置,則顯示headerTv
        if (position == CommUtil.getPositionForSection(position, cityBeanList)) {
            viewHolder.contentTv.setVisibility(View.VISIBLE);
            viewHolder.headerTv.setVisibility(View.VISIBLE);
            viewHolder.headerTv.setText(bean.getLetterName());
        } else {
            viewHolder.headerTv.setVisibility(View.GONE);
            viewHolder.contentTv.setVisibility(View.VISIBLE);
        }
        viewHolder.contentTv.setText(bean.getCityName());
        return convertView;
    }

    /**
     * vh
     */
    class ViewHolder {
        TextView headerTv;
        TextView contentTv;
    }
}

MainActivity:

package com.example.junweiliu.commindexdemo;

import android.app.Activity;
import android.os.Bundle;
import android.widget.ListView;
import android.widget.TextView;

import com.example.junweiliu.commindexdemo.adapter.CityAdapter;
import com.example.junweiliu.commindexdemo.bean.CityBean;
import com.example.junweiliu.commindexdemo.util.CommUtil;
import com.example.junweiliu.commindexdemo.widget.SideBar;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends Activity {
    /**
     * 城市列表數據
     */
    private List<CityBean> cityBeanList = new ArrayList<>();
    /**
     * 城市lv
     */
    private ListView cityList;
    /**
     * 索引欄
     */
    private SideBar mSideBar;
    /**
     * 顯示的tv
     */
    private TextView mShowTv;
    /**
     * 適配器
     */
    private CityAdapter mCityAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initData();
        initView();
    }


    /**
     * 初始化數據
     */
    private void initData() {
        CityBean bean1 = new CityBean("安徽", "A", "安徽故事");
        CityBean bean2 = new CityBean("安徽1", "A", "安徽1故事");
        CityBean bean3 = new CityBean("安徽2", "A", "安徽2故事");
        CityBean bean4 = new CityBean("北京", "B", "北京故事");
        CityBean bean5 = new CityBean("北京1", "B", "北京1故事");
        CityBean bean6 = new CityBean("北京2", "B", "北京2故事");
        CityBean bean7 = new CityBean("重慶", "C", "重慶故事");
        CityBean bean8 = new CityBean("重慶1", "C", "重慶1故事");
        CityBean bean9 = new CityBean("重慶2", "C", "重慶2故事");
        CityBean bean10 = new CityBean("貴州", "G", "貴州故事");
        CityBean bean11 = new CityBean("貴州1", "G", "貴州2故事");
        CityBean bean12 = new CityBean("貴州2", "G", "貴州3故事");
        CityBean bean13 = new CityBean("天津", "T", "天津故事");
        CityBean bean14 = new CityBean("天津1", "T", "天津1故事");
        CityBean bean15 = new CityBean("天津2", "T", "天津2故事");

        cityBeanList.add(bean1);
        cityBeanList.add(bean2);
        cityBeanList.add(bean3);
        cityBeanList.add(bean1);
        cityBeanList.add(bean2);
        cityBeanList.add(bean3);
        cityBeanList.add(bean4);
        cityBeanList.add(bean5);
        cityBeanList.add(bean6);
        cityBeanList.add(bean4);
        cityBeanList.add(bean5);
        cityBeanList.add(bean6);
        cityBeanList.add(bean7);
        cityBeanList.add(bean8);
        cityBeanList.add(bean9);
        cityBeanList.add(bean7);
        cityBeanList.add(bean8);
        cityBeanList.add(bean9);
        cityBeanList.add(bean10);
        cityBeanList.add(bean11);
        cityBeanList.add(bean12);
        cityBeanList.add(bean10);
        cityBeanList.add(bean11);
        cityBeanList.add(bean12);
        cityBeanList.add(bean13);
        cityBeanList.add(bean14);
        cityBeanList.add(bean15);
        cityBeanList.add(bean13);
        cityBeanList.add(bean14);
        cityBeanList.add(bean15);
    }

    /**
     * 初始化控件
     */
    private void initView() {
        cityList = (ListView) findViewById(R.id.lv_city);
        mSideBar = (SideBar) findViewById(R.id.sb_city);
        mShowTv = (TextView) findViewById(R.id.tv_city_show);
        mCityAdapter = new CityAdapter(MainActivity.this, cityBeanList);
        cityList.setAdapter(mCityAdapter);
        // 設置需要顯示的索引欄內容
        mSideBar.setLetter(CommUtil.getLetters(cityBeanList));
        // 設置需要顯示的提示框
        mSideBar.setTextView(mShowTv);
        mSideBar.setOnTouchingLetterChangedListener(new SideBar.OnTouchingLetterChangedListener() {
            @Override
            public void onTouchingLetterChanged(String s) {
                int position = CommUtil.getLetterPosition(cityBeanList, s);
                if (position != -1) {
                    cityList.setSelection(position);
                }
            }
        });
    }
}

佈局文件activity_main:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
        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"
        tools:context="com.example.junweiliu.commindexdemo.MainActivity">

    <!--城市列表-->
    <ListView
            android:id="@+id/lv_city"
            android:layout_width="match_parent"
            android:layout_height="match_parent">
    </ListView>
    <!--索引欄-->
    <com.example.junweiliu.commindexdemo.widget.SideBar
            android:id="@+id/sb_city"
            android:layout_width="wrap_content"
            android:layout_height="200dp"
            android:layout_alignParentRight="true"
            android:layout_centerVertical="true"
            app:sideTextSize="13sp"/>
    <!--顯示的字母-->
    <TextView
            android:id="@+id/tv_city_show"
            android:layout_width="80dp"
            android:layout_height="80dp"
            android:layout_centerInParent="true"
            android:background="#3F51B5"
            android:gravity="center"
            android:textColor="#ffffff"
            android:textSize="25sp"
            android:visibility="gone"
    />
</RelativeLayout>

適配器佈局item_city:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:orientation="vertical">

    <!-- 索引頭 -->
    <TextView
            android:id="@+id/tv_item_citys_header"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="#E3E3E3"
            android:padding="15dp"
            android:text="A"
            android:textColor="#666666"
            android:textSize="14sp"
            android:visibility="gone"/>

    <!-- 內容 -->
    <TextView
            android:id="@+id/tv_item_citys_context"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="#ffffff"
            android:padding="15dp"
            android:textColor="#000000"
            android:textSize="14sp"
            android:visibility="gone"/>

</LinearLayout>

源碼下載

源碼地址

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章