Android可以纵向滚动的textView
2016-03-21 12:51
447 查看
在项目上遇到这么一个需求
1、一段文字,最多显示两行,点击某个单词进入A页面,点击另一个单词进入B页面,
2、如果句子太长的话,让这个textView可以上下滚动,但textView的高度始终是原来两行的高度,不能增高,并且单词的点击事件不能消失,
3、由于这个textView是套在recyclerVIew中的,在滚动textView的时候还不能让recyclerView滚动。而且为了性能问题,不能采用scrollView内嵌textView的方式,所以采用了下面的方法。
思路比较简单,实现textView中具体某个单词的点击事件只需要用textView.append(一个可点击的继承spannable的类就好)
首先这个textView的布局
注意这里的maxLines=2也就是说最多显示两行,这里这么设置主要为了后面拿到这个textView高度设置的
下面就是初始化这个TextView,在代码里设置可以点击的单词,并且执行textView.setMovementMethod(),让TextView可以纵向滚动
下面是最重要的LinkMovementMethod的写法了,用了这个类就可以实现textView的纵向滚动
并且实现了在recyclerView内滚动事件不冲突,并且在滚动之后仍然保持点击事件,并且防止了点击事件的误触发
1、一段文字,最多显示两行,点击某个单词进入A页面,点击另一个单词进入B页面,
2、如果句子太长的话,让这个textView可以上下滚动,但textView的高度始终是原来两行的高度,不能增高,并且单词的点击事件不能消失,
3、由于这个textView是套在recyclerVIew中的,在滚动textView的时候还不能让recyclerView滚动。而且为了性能问题,不能采用scrollView内嵌textView的方式,所以采用了下面的方法。
思路比较简单,实现textView中具体某个单词的点击事件只需要用textView.append(一个可点击的继承spannable的类就好)
首先这个textView的布局
<TextView android:id="@+id/ctv_card_title" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:layout_weight="1" android:maxLines="2" android:textSize="15sp" android:text="John Doe uploaded 4 photos" android:textColor="#505256" />
注意这里的maxLines=2也就是说最多显示两行,这里这么设置主要为了后面拿到这个textView高度设置的
下面就是初始化这个TextView,在代码里设置可以点击的单词,并且执行textView.setMovementMethod(),让TextView可以纵向滚动
public static void initCardHeader(final Activity activity, final TextView textView, String userName, String middleText, String restaurantName, final long userId , final long restaurantId , TextView ctv_reviewPhoto_count, long reviewCount , int photoCount){ if(textView==null||activity==null)return; textView.setText("");//清空textView SpannableString userNameSpan = new SpannableString(userName); userNameSpan.setSpan(new ClickableSpan() { @Override public void updateDrawState(TextPaint ds) { super.updateDrawState(ds); ds.setColor(0xFF505256); ds.setAntiAlias(true);//抗锯齿 ds.setUnderlineText(false); ds.setFakeBoldText(true);//设置粗体 } @Override public void onClick(View widget) {//在这里复写点击事件 JLogUtils.i("Alex","点击了用户名,用户id是"+userId); if(QravedApplication.getAppConfiguration().getUserId()!=userId)return; JLogUtils.i("Alex","准备跳转到myQraved"); if(activity instanceof HomeActivity)((HomeActivity)activity).switchFragment(HomeActivity.FRAGMENT_TYPE_HOME_HOME, HomeActivity.FRAGMENT_TYPE_HOME_MYPROFILE_MYLIST); } }, 0, userNameSpan.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); textView.append(userNameSpan); if(activity instanceof HomeActivity || activity instanceof JournalCommentsActivity) { textView.append(middleText);//添加中间部分 SpannableString restaurantSpan = new SpannableString(restaurantName); restaurantSpan.setSpan(new ClickableSpan() { @Override public void updateDrawState(TextPaint ds) { super.updateDrawState(ds); ds.setColor(0xFF505256); ds.setAntiAlias(true);//抗锯齿 ds.setUnderlineText(false); ds.setFakeBoldText(true);//设置粗体 } @Override public void onClick(View widget) {//在这里复写点击事件 JLogUtils.i("Alex", "点击了餐馆名字,餐馆id是" + restaurantId); Intent intent = new Intent(); intent.putExtra("restaurantId", String.valueOf(restaurantId)); intent.setClass(activity, RestaurantDetailActivity.class); activity.startActivity(intent); activity.overridePendingTransition(R.anim.enter_righttoleft, R.anim.exit_righttoleft); } }, 0, restaurantSpan.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); textView.append(restaurantSpan); } textView.setMovementMethod(AlxLinkMovementMethod.getInstance());//让textView可以纵向滚动,里面这个类在本文有源码 ctv_reviewPhoto_count.setText(reviewCount + (reviewCount > 1 ? " reviews" : " review") + " - " + photoCount + (photoCount > 1 ? " photos" :" photo")); //让两行以上可以滚动的方法 ViewTreeObserver observer = textView.getViewTreeObserver(); observer.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { // TODO Auto-generated method stub Layout layout2 = textView.getLayout(); if(textView!=null&&layout2!=null){ int lines = layout2.getLineCount(); if(lines!=2)return;//如果不到两行,就不管了 int textViewHeight = textView.getHeight();//得到两行时候的textView的高度 textView.setMaxHeight(textViewHeight);//设置textView的最大高度为现在这样 textView.setMaxLines(Integer.MAX_VALUE);//不限制textView的行数,这样才能够滚动起来 } } }); }
下面是最重要的LinkMovementMethod的写法了,用了这个类就可以实现textView的纵向滚动
并且实现了在recyclerView内滚动事件不冲突,并且在滚动之后仍然保持点击事件,并且防止了点击事件的误触发
package com.imaginato.qravedconsumer.widget; import android.text.Layout; import android.text.Selection; import android.text.Spannable; import android.text.method.LinkMovementMethod; import android.text.method.MovementMethod; import android.text.style.ClickableSpan; import android.view.MotionEvent; import android.widget.TextView; import com.imaginato.qravedconsumer.utils.JLogUtils; /** * Created by Administrator on 2016/3/21. */ public class AlxLinkMovementMethod extends LinkMovementMethod{ @Override public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) { if (widget.getLayout().getLineCount() > 1) { JLogUtils.i("Alex", "大于一行"); boolean ret = mOnTouchEvent(widget, buffer, event); widget.getParent().requestDisallowInterceptTouchEvent(true);//阻止父层的View截获touch事件 if(event.getAction()==MotionEvent.ACTION_UP) widget.getParent().requestDisallowInterceptTouchEvent(false); JLogUtils.i("Alex","ret是"+ret); return true; } else {//小于一行 boolean ret = super.onTouchEvent(widget, buffer, event); JLogUtils.i("Alex", "小于一行"+ret); return ret; } } private boolean couldClick = true;//现在是否响应点击事件 private float lastY; private boolean mOnTouchEvent(TextView widget, Spannable buffer, MotionEvent event){ int action = event.getAction(); switch (event.getAction()){ case MotionEvent.ACTION_MOVE: if(Math.abs(event.getY()-lastY)>10)couldClick = false;//只有在发生了滚动的时候才禁止点击事件 break; } if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_DOWN) { int x = (int) event.getX(); int y = (int) event.getY(); x -= widget.getTotalPaddingLeft(); y -= widget.getTotalPaddingTop(); x += widget.getScrollX(); y += widget.getScrollY(); Layout layout = widget.getLayout(); int line = layout.getLineForVertical(y); int off = layout.getOffsetForHorizontal(line, x); ClickableSpan[] link = buffer.getSpans(off, off, ClickableSpan.class); if (link.length != 0) { if (action == MotionEvent.ACTION_UP) { JLogUtils.i("Alex","现在up了"+couldClick); if(couldClick)link[0].onClick(widget); } else if (action == MotionEvent.ACTION_DOWN) { lastY = event.getY(); Selection.setSelection(buffer, buffer.getSpanStart(link[0]), buffer.getSpanEnd(link[0])); couldClick = true; } return true; } else { Selection.removeSelection(buffer); } } return super.onTouchEvent(widget, buffer, event); } private static AlxLinkMovementMethod hahaInstance; public static MovementMethod getInstance() { if (hahaInstance == null) hahaInstance = new AlxLinkMovementMethod(); return hahaInstance; } }
相关文章推荐
- Android Studio中集成fresco,解决冲突的问题。
- Android Studio:Error:(23, 17) Failed to resolve: junit:junit:4.12
- Unsupported major.minor version 52.0
- Android Studio设置自动编译工程
- 怎样查看android SDK文档
- Android笔记——Activity生命周期与数据传递
- 编译vlc android arm64-v8a
- Span 介绍及使用(二)
- Span 介绍及使用(一)
- Android基于Facebook Rebound的动画效果框架Backboard demo (非常炫酷)
- Android静默安装和静默卸载
- Android实现音乐示波器、均衡器、重低音和音场功能
- android:process 讲解
- Android性能测试:CPU内存监控工具APT
- Android 引导页动态加载(多页面 ViewPager联动RadioButton)
- AndroidStudio权威教程 AS添加第三方库的6种方式(Jar module so等)
- Android 打开地图并显示指定的经纬度
- Android开发:使用Glide动态加载圆形图片和圆角图片
- Android更改桌面应用程序launcher的两种方式
- Android TextView特殊效果