自訂的TextView,使部分內容擁有點擊事件,並在點擊內容上方出現對應的詞義等資訊,textview詞義
直接看:
上面圖中是一個TextView,註冊部分內容(KeyWord)是其擁有點擊事件,並通過計算KeyWord的座標,顯示KeyWord的想要的一些資訊
/** * 一個TextView中包含一個可以點擊的KeyWord(關鍵詞),並通過點擊關鍵詞,在對應關鍵詞位置正上方展示關鍵詞對應的解釋等邏輯 * @author DuGuang * */public class MainActivity extends Activity {private KeyWordTextView mTvKeyWord;private ShowHideView mShowHideView;private DotView mDotView;private int mStatusBarHeight; // 手機狀態列高度private int mTitleBarHeight;//手機標題列的高度private RelativeLayout mLlMain;private String mHide = "愛";private String mStartStr;//關鍵詞前面的欄位//private String mStartStr = null;private String mKeyWord = "love"; //關鍵詞private String mEndStr ;//關鍵詞後面的欄位//private String mEndStr = null;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);initView();initData();}/** * 初始化View */private void initView() {mTvKeyWord = (KeyWordTextView) findViewById(R.id.mTvKeyWord);mLlMain = (RelativeLayout) findViewById(R.id.mLlMain);mShowHideView = new ShowHideView(this);mDotView = new DotView(this);RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT,RelativeLayout.LayoutParams.WRAP_CONTENT);mShowHideView.setLayoutParams(params);mDotView.setLayoutParams(params);mShowHideView.setVisibility(View.INVISIBLE);mLlMain.addView(mShowHideView);mLlMain.addView(mDotView);}/** * 填充資料 */private void initData() {mStartStr = "Whatever is worth doing is worth haha zhen de ke yi me, hao xi fan! Whatever is worth doing is worth haha zhen de ke yi me, hao xi fan! Whatever is worth doing is worth haha zhen de ke yi me, hao xi fan! Whatever is worth doing is worth haha zhen de ke yi me, hao xi fan! Whatever is worth doing is worth haha zhen de ke yi me, hao xi fan! Whatever is worth doing is worth haha zhen de ke yi me, hao xi fan! ";mEndStr = " Whatever is worth doing is worth doing well.";//這裡開啟子線程是為擷取狀態列和標題列的高度mTvKeyWord.post(new Runnable() {@Overridepublic void run() {getBarHeight();mTvKeyWord.setAllString(mStartStr, mKeyWord, mEndStr, mHide,mStatusBarHeight, mTitleBarHeight, mShowHideView, mDotView);}});}/** * 擷取手機狀態列和標題列的高度 */private void getBarHeight() {Rect frame = new Rect();getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);Window window = getWindow();// 狀態列的高度mStatusBarHeight = frame.top;// 標題列跟狀態列的總體高度int contentViewTop = window.findViewById(Window.ID_ANDROID_CONTENT).getTop();// 標題列的高度:用上面的值減去狀態列的高度及為標題列高度mTitleBarHeight = contentViewTop - mStatusBarHeight;Log.i("dg", mStatusBarHeight + "..." + contentViewTop + "..."+ mTitleBarHeight);}}
/** * 一個TextView中包含一個可以點擊的KeyWord(關鍵詞),並通過點擊關鍵詞,在對應關鍵詞位置正上方展示關鍵詞對應的解釋等邏輯 * * @author DuGuang * @date 2015.1.11 * */public class KeyWordTextView extends TextView {protected static final String TAG = KeyWordTextView.class.getSimpleName();private Context mContext;private String mHide; // 關鍵詞的提示內容private ShowHideView mShowHideView;//show關鍵詞解釋private DotView mDotView;//畫一個圓點,效驗mShowHideView展示的位置是否正確private String mStartStr, mKeyWord, mEndStr;int mYStartTop;// 關鍵詞第一個字元頂部y座標int mYStartBottom;// 關鍵詞第一個字元底部y座標float mXStartLeft;// 關鍵詞第一個字元左邊x座標float mXStartRight;// 關鍵詞第一個字元右邊x座標int mYEndTop;// 關鍵詞最後一個字元頂部y座標int mYEndBottom;// 關鍵詞最後一個字元底部y座標float mXEndLeft;// 關鍵詞最後一個字元左邊x座標float mXEndRight;// 關鍵詞最後一個字元右邊x座標private Layout mLayout;private int mStartPosition; // 關鍵詞起始的位置private int mEndPosition; // 關鍵詞結束的位置private int mStatusBarHeight; //手機狀態列高度private int mTitleBarHeight;//手機標題列的高度private SpannableString mSpStr;//用於給KeyWord單獨加顏色和底線的類@SuppressLint("NewApi")public KeyWordTextView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);this.mContext = context;}public KeyWordTextView(Context context, AttributeSet attrs) {super(context, attrs);this.mContext = context;}public KeyWordTextView(Context context) {super(context);this.mContext = context;}/** * 填充段落內容 * * @param startStr * * @param keyWord * * @param endStr * *//** * @param startStr * @param keyWord * @param endStr * @param hide * @param mDotView * @param mTitleBarHeight * @param mShowHideView *//** * @param startStr關鍵詞之前顯示的內容,如果沒有則傳null * @param keyWord關鍵詞,可以點擊的詞 * @param endStr關鍵詞之後顯示的內容,如果沒有則傳null * @param hide展示關鍵詞的解釋欄位 * @param statusBarHeight狀態列的高度 * @param titleBarHeight標題列的高度 * @param showHideView展示關鍵詞的View * @param dotView畫一個圓點,效驗mShowHideView展示的位置是否正確 */public void setAllString(String startStr, String keyWord, String endStr, String hide, int statusBarHeight, int titleBarHeight,ShowHideView showHideView, DotView dotView) {this.mStartStr = startStr;this.mKeyWord = keyWord;this.mEndStr = endStr;this.mHide = hide;this.mStatusBarHeight = statusBarHeight;this.mShowHideView = showHideView;this.mTitleBarHeight = titleBarHeight;this.mDotView = dotView;setKeyWordClick();initData();getTextLayout();}/** * 填充相關資料 */private void initData() {// 計算關鍵詞的起始位置mStartPosition = StringUtil.isNotEmpty(mStartStr) ? mStartStr.length() + 1 : 1;//計算關鍵詞結束所在位置mEndPosition = StringUtil.isNotEmpty(mEndStr) ?mStartPosition + mKeyWord.length()+1 : mStartPosition + mKeyWord.length() -1 ;setText(mStartStr);append(mSpStr);append(StringUtil.isNotEmpty(mEndStr) ? mEndStr : "");setMovementMethod(LinkMovementMethod.getInstance());// 相當於註冊關鍵詞的點擊事件(開始響應點擊事件)}/** * 擷取對應TextView的layout屬性 */private void getTextLayout() {// view變化監聽器ViewTreeObserver介紹ViewTreeObserver vto = getViewTreeObserver();vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {@Overridepublic void onGlobalLayout() {mLayout = getLayout();Rect bound = new Rect();int line = mLayout.getLineForOffset(mStartPosition);mLayout.getLineBounds(line, bound);mYStartTop = bound.top;mYStartBottom = bound.bottom;mXStartLeft = mLayout.getPrimaryHorizontal(mStartPosition);mXStartRight = mLayout.getSecondaryHorizontal(mStartPosition);}});}/** * 設定關鍵詞的點擊事件 */private void setKeyWordClick() {mSpStr = new SpannableString(mKeyWord);mSpStr.setSpan(new ClickableSpan() {@Overridepublic void updateDrawState(TextPaint ds) {super.updateDrawState(ds); ds.setColor(Color.BLUE); //設定文字顏色ds.setUnderlineText(true); // 設定底線}@Overridepublic void onClick(View widget) {Log.d("", "onTextClick........被點擊了");Log.i(TAG, "mYStartTop >>> " + mYStartTop);Log.i(TAG, "mYStartBottom >>> " + mYStartBottom);Log.i(TAG, "mXStartLeft >>> " + mXStartLeft);Log.i(TAG, "mXStartRight >>> " + mXStartRight);int[] location1 = new int[2];//getLocationInWindow(location1);getLocationOnScreen(location1);Log.i(TAG, "location1[0] >>> " + location1[0]);Log.i(TAG, "location1[1] >>> " + location1[1]);getKeyWordEndInfo();//RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);//params.leftMargin = 100;//params.topMargin = 100;//mdot.setLayoutParams(params);RelativeLayout.LayoutParams params2 = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);params2.leftMargin = (int)(mXStartLeft+(mXEndRight - mXStartLeft)/2)- mShowHideView.getWidth()/2;params2.topMargin = (int)location1[1] - mStatusBarHeight - mTitleBarHeight + mYStartTop - mShowHideView.getHeight();mShowHideView.setLayoutParams(params2);mShowHideView.setPosition(mHide);mDotView.setPosition((int)(mXStartLeft+(mXEndRight - mXStartLeft)/2), (int)location1[1] - mStatusBarHeight - mTitleBarHeight + mYStartTop);}}, 0, mKeyWord.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);}/** * 擷取關鍵詞最後一個字元的X,Y的相關資訊 */public void getKeyWordEndInfo(){mLayout = getLayout();Rect bound = new Rect();int line = mLayout.getLineForOffset(mEndPosition);mLayout.getLineBounds(line, bound);mYEndTop = bound.top;mYEndBottom = bound.bottom;mXEndLeft = mLayout.getPrimaryHorizontal(mEndPosition);mXEndRight = mLayout.getSecondaryHorizontal(mEndPosition);Log.i(TAG, "mYEndTop >>> " + mYEndTop);Log.i(TAG, "mYEndBottom >>> " + mYEndBottom);Log.i(TAG, "mXEndLeft >>> " + mXEndLeft);Log.i(TAG, "mXEndRight >>> " + mXEndRight);}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);}}
/** * 點擊KeyWord後,顯示KeyWord的相關資訊的View * @author DuGuang * */public class ShowHideView extends LinearLayout{private Context mContext;private TextView mTvShowHide;@SuppressLint("NewApi")public ShowHideView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);this.mContext = context;initView();}public ShowHideView(Context context, AttributeSet attrs) {super(context, attrs);this.mContext = context;initView();}public ShowHideView(Context context) {super(context);this.mContext = context;initView();}public void setPosition(String hide){mTvShowHide.setText(hide);setVisibility(View.VISIBLE);}/** * 填充自訂的XML布局 */public void initView() {View view = View.inflate(mContext, R.layout.item_popwin_start_hide,ShowHideView.this);mTvShowHide = (TextView) view.findViewById(R.id.tv_paly_hide);}}
/** * 畫一個點,用來效驗ShowHideView顯示的位置是否正確 * @author DuGuang * */public class DotView extends View{private static final String TAG = DotView.class.getSimpleName();private Context mContext;private float mX;private float mY;@SuppressLint("NewApi")public DotView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);this.mContext = context;}public DotView(Context context, AttributeSet attrs) {super(context, attrs);this.mContext = context;}public DotView(Context context) {super(context);this.mContext = context;}public void setPosition(int x, int y){mX = x;mY = y;invalidate();}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);Paint paint = new Paint();paint.setStyle(Style.FILL);paint.setStrokeWidth(20);paint.setColor(mContext.getResources().getColor(R.color.blue));Log.i(TAG, "mX >>> "+mX);Log.i(TAG, "mY >>> "+mY);canvas.drawPoint(mX, mY, paint);}}
Demo:http://download.csdn.net/detail/u011112840/8350491
Github地址:https://github.com/z56402344/CustomTextView