热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Android,TextView优雅显示长文本、富文本

Android,TextView优雅显示长文本、富文本Android提供了TextView这个类作为Android开发当中展示文字的工作,最近笔者在做类似于一个展示类型的APP,发现TextV

Android,TextView优雅显示长文本、富文本

Android提供了TextView这个类作为Android开发当中展示文字的工作,最近笔者在做类似于一个展示类型的APP,发现TextView这个类真的有点力不从心,好多的功能都让笔者特别头疼,于是就有了今天这篇技术博客。

原生的APi当中提供了TextView这个控件供开发者使用,一般需求都不在话下,可以设置显示文本的字体大小,字体颜色以及字体的显示格式,如:密码格式、数字格式等等。但是在千变万化的开发当中,还是不能满足开发者的需求,比如控制下拉的长文本,以及富文本。我们先来看几种需求。

这里写图片描述

图1

这里述

图2

上面看到了几点需求,还有好多,笔者相信各位看客心中都懂,所以就不展示太多了,我们今天要做到就是通过几种方式来优化我们TextView,好吧,我们开始。


1、TextView实现长文本的分段展示。

长文本:这个没什么好解释的,就是比较长的文本。直接显示就OK,但是我们知道Android当中的屏幕尺寸是有限的,我们要在有限的屏幕内合理的显示很多的内容,当然这个是侧滑菜单栏出现的原因。我们要让TextView通过用户的交互来显示合理的内容,比如在用户并不对该文本关系的前提,显示重要的前几行就OK ,如果用户想看文本内容,用户可以通过点击当前的TextView进行显示其与的内容,根据这个简单的需求,我们来对TextView进行定制。

首先我们先计划一下我们怎么对当前的TextView进行定制呢!

  • 1、我们继承一个现有的ViewGroup,当中含有一个Button、TextView。实际让Button去控制TextView的显示方式。
  • 2、我们初始化的时候可以根据TextView的长度,来决定是否显示Button,因为我们知道TextView在我们有限的空间里面可以完全显示的时候,也就不需要下拉的功能。
  • 3、通过TextView可显示的行数,完全显示的行数去测量TextView的高度。
  • 4、通过Button的点击去切换可显示的行数、完全显示的行数
  • 5、加入动画,笔者这里加入的属性动画
  • 6、解决不友好的BUG,类似于ViewGroup改变,而当ViewGroup改变动画结束,TextView才完全显示,这里会贴图给看客展示。
  • 7、添加回调定制完成,效果图展示

1、继承ViewGroup开始定制

/**
* 用于显示长文本,可以展开的TextView
* Created by suansuan on 2017/9/18.
*/

public class PullDownTextView extends LinearLayout implements View.OnClickListener{
private TextView mTextView ;
private ImageButton mImageButton;
}

我们这里选择的是LinearLayout,原因就是我们TextView和Button排列方式是线性布局。

2、初始化

public class PullDownTextView extends LinearLayout implements View.OnClickListener{
//是否处于展开状态。默认为隐藏
private boolean isPull ;

private TextView mTextView ;
private ImageButton mImageButton;

/** ImageButton切换的两种图片 */
private Drawable mPullDownDrawable ;
private Drawable mUpDownDrawable ;

/** 初始化PullDownTextView */
private void initPullDownTextView() {
mPullDownDrawable = getDrawable(R.drawable.ic_pull_small_light);
mUpDownDrawable = getDrawable(R.drawable.ic_not_small_light);
setOrientation(LinearLayout.VERTICAL);
//默认隐藏
setVisibility(View.GONE);
}

/** 当加载完XML布局时回调 */
@Override
protected void onFinishInflate() {
super.onFinishInflate();
initPullDownTextView();
mTextView = (TextView) this.getChildAt(0);
mImageButton = (ImageButton) this.getChildAt(1);
mImageButton.setOnClickListener(this);
mImageButton.setImageDrawable(isPull ? mUpDownDrawable : mPullDownDrawable);
}

@Override
public void setOrientation(int orientation) {
if(orientation == LinearLayout.HORIZONTAL){
throw new IllegalArgumentException("参数错误:当前控件,不支持水平");
}
super.setOrientation(orientation);
}
}

我们对当前的ViewGroup进行初始化设置。对Button的图片进行初始化,以及事件的初始化

3、测量

public class PullDownTextView extends LinearLayout implements View.OnClickListener{
/** 位置大小相关属性 */
private int mTextViewPullHeight ; //textView显示全部也就是下拉状态的高度
private int mTextViewNotPullHeight ;

private boolean isPull ; //是否处于展开状态。默认为隐藏
private boolean isReLayout ; //当前布局是否重新绘制。
private boolean isAnimator ; //是否处于动画当中
private boolean isMaxHeightMeasure; //是否进行TextView最大行数的测量
private boolean isMinHeightMeasure; //是否进行TexView可见行数的测量

private TextView mTextView ;
private ImageButton mImageButton;

/** ImageButton切换的两种图片 */
private Drawable mPullDownDrawable ;
private Drawable mUpDownDrawable ;

private int mTextVisibilityCount = 3; //隐藏时 TextView可以显示的最大的行数
private int mAnimatorDuration = 500 ;

```
/** 测量方发,测量自己的宽高,测量孩子的宽高 */
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//没有内容的时候,
if(!isReLayout || getVisibility() == View.GONE){
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
return ;
}

//有内容,但是内容比较短的时候,正常显示TextView,但是相应的隐藏ImageButton
if(mTextView.getLineCount() <= mTextVisibilityCount){
mTextView.setVisibility(View.VISIBLE);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
return ;
}

//有内容,并且显示的内容比较长的时候,这里我们显示TextView、ImageButton。
mImageButton.setVisibility(View.VISIBLE);
if(!isMaxHeightMeasure && mTextViewPullHeight == 0){
mTextView.setMaxLines(Integer.MAX_VALUE);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mTextViewPullHeight = mTextView.getMeasuredHeight() ;
isMaxHeightMeasure = true ;
}

if(!isMinHeightMeasure && mTextViewNotPullHeight == 0){
mTextView.setMaxLines(mTextVisibilityCount);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mTextViewNotPullHeight = mTextView.getMeasuredHeight();
isMinHeightMeasure = true ;
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}

在这里测量为什么只测量一次呢,因为后续我们会通过属性动画去改变TextView的高度,而我们改变后,我们获取就会导致我们获取到的高度不是定值,而是改变后的值。测量这里我们主要分为三种情况,上述代码当中注释也说的很清楚

  • 1、没有内容的时候,
  • 2、有内容,但是内容比较短的时候,正常显示TextView,但是相应的隐藏ImageButton
  • 3、有内容,并且显示的内容比较长的时候,这里我们显示TextView、ImageButton。

4、点击事件

@Override
public void onClick(View v) {
if(isAnimator){
return ;
}
if(isPull){
startAnimator(mTextView, mTextViewPullHeight, mTextViewNotPullHeight);
} else {
startAnimator(mTextView, mTextViewNotPullHeight, mTextViewPullHeight);
}
//下拉,或者上拉的时候的回调
if(this.mOnTextViewPullListener != null){
this.mOnTextViewPullListener.textViewPull(mTextView, isPull);
}
isPull = !isPull ;
mImageButton.setImageDrawable(isPull ? mUpDownDrawable : mPullDownDrawable);
}

根据用户点击状态去切换Button的图标,还有根据刚刚测量的高度进行开启动画

5、开启动画

    /**
* 开始动画
*/

private void startAnimator(final TextView view, int startHeight, int endHeight){
ValueAnimator valueAnimator = ValueAnimator.ofInt(startHeight , endHeight ).setDuration(mAnimatorDuration);
valueAnimator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {}
@Override
public void onAnimationEnd(Animator animation) {
isAnimator = false ;
}
@Override
public void onAnimationCancel(Animator animation) {}
@Override
public void onAnimationRepeat(Animator animation) {}
});
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int animatedValue = (int) animation.getAnimatedValue();
ViewGroup.LayoutParams params = view.getLayoutParams();
params.height = animatedValue ;
//这句,让TextView文本的高度随TextView高度进行变化
view.setMaxHeight(animatedValue);
view.setLayoutParams(params);
}
});
isAnimator = true ;
valueAnimator.start();
}

这个地方有一个坑,笔者也是想了很久,才弄明白的,说不太清楚,看下效果图吧。为了各位看客能很清楚的BUG,笔者在这里加入不同的背景。
这里写图片描述
这种效果就是在刚刚开始动画的时候,应该加入

view.setMaxHeight(animatedValue);

6、回调接口

   /** TextView展开回调 */
public interface OnTextViewPullListener{
void textViewPull(TextView textView, boolean isPull) ;
}

public void setOnTextViewPullListener(OnTextViewPullListener listener){
this.mOnTextViewPullListener= listener ;
}

7、在MainActivity当中使用

public class MainActivity extends AppCompatActivity {

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

PullDownTextView text1 = (PullDownTextView)findViewById(R.id.expand_text_view);
text1.setText(getString(R.string.long_text1));

PullDownTextView text2 = (PullDownTextView)findViewById(R.id.expand1_text_view);
text2.setText(getString(R.string.long_text1));
}
}

这里没有什么好说的,相信各位看客都懂。
这就是大体的流程,回调接口就是在onClick事件回调的,上述代码也有说明。
到这里就差不多了,源码在文章末尾给出,看一下我们的效果吧

这里写图片描述


2、TextView显示富文本

我们在开始编码之前,我们先来了解一下什么是富文本,
富文本(Rich Text Format):这个有些开发者比较陌生,那么什么是富文本呢?其实就是一段带有自己的格式的文本。这么说有点抽象,我们来举个例子,其实就是我们常用的Word编辑器所写的文本,每一个字都是带有格式的。我们看下面的一个例子就理解了什么是富文本。

Hello!
This is some bold text.

仔细观察,上述的一段文字是带有格式。这就是我们常见的富文本。现在我们看富文本的相应代码

{\rtf1\ansi
Hello!\par
This is some {\b bold} text.\par
}

上述的富文本格式代码,貌似存在一定的规则可寻。什么规则呢,这里大体的描述一下,因为笔者这里语法也没有太多的深入,反斜线(\)标着这个RTE(富文本)控制的开始。(\par)表示开始新的一行,有点类似于HTML当中的标签了。(\b)将文字粗体显示。({})大括号定义了一个群组,上述例子中使用了一个群组来限制代码\b的作用范围。合法的RTF文档是一个以代码\rtf开始的群组。

了解了基本的什么是富文本之后,我们开始思考在本文开后的图1里面效果,如果让大家在Wold编辑器当中编写,会非常简单。当然Google也考虑到了这一种情况,所以我们不需要定制View就可以达到这种效果,Google为我们提供一个类用来封装我们带有格式的富文本,然后丢给TextView进行显示就OK,

1、Google提供富文本封装类Spannable

Spannable是一个接口,有两个实现类分别是SpannableStringSpannableStringBuilder,我们知道我们以后要使用的话,肯定就是这里面的这两个类啦。那么这两个类有什么区别呢,其实和我们早前学过的String,和StringBuilder是一样的,一个为定长字符串,一个为可变字符串的区别,可以根据看客自己的需求去选择

Spannable里面定义了两个方法,和一个静态工厂,通过静态工厂拿到Spannable默认实现类是SpannableString。具体代码如下所示:
Spannable.java

 public static class Factory {
private static Spannable.Factory sInstance = new Spannable.Factory();

/**
* Returns the standard Spannable Factory.
*/

public static Spannable.Factory getInstance() {
return sInstance;
}

/**
* Returns a new SpannableString from the specified CharSequence.
* You can override this to provide a different kind of Spannable.
*/

public Spannable newSpannable(CharSequence source) {
return new SpannableString(source);
}
}

Spannable里面定义了两个方法,分别是:

public void setSpan(Object what, int start, int end, int flags);
public void removeSpan(Object what);

这里有几个参数,需要说一下,

参数 含义
what 样式
start 该样式作用范围的起始位置
end 该样式作用范围的结束位置
flags 模式,

最后一个参数的模式,相对的有点抽象,其实看客可以理解成为枚举,也就是说模式是系统为我们定义好的,让我去选择使用就OK了。在系统当中由Spanned给出。

Spanned.SPAN_INCLUSIVE_INCLUSIVE 起始结束都包括
Spanned.SPAN_EXCLUSIVE_INCLUSIVE 起始不包括,结束包括
Spanned.SPAN_INCLUSIVE_EXCLUSIVE 起始包括,结束不包括
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE 起始结束都不包括

1.1、获取Spannable实例

我们刚刚看过源码,知道了Spannable内部又一个静态的工厂类,那我们就使用这个类来获取实例。

Spannable spannable = Spannable.Factory.getInstance().newSpannable(string);

1.2、Google为我们提供的样式

其实这里的样式是特别的多的,Google主要按照分类,分成了两大类,分别是字体的样式,和段落的样式。笔者在这里找几个常用的到的进行说明,其他的请各位看客自行去了解CharacterStyle, ParagraphStyle的实现子类,好找出看客所需要的样式。

1.3、颜色相关

颜色相关主要分为一个字体的颜色(ForegroundColorSpan),一个背景的颜色(BackgroundColorSpan)。
这里写图片描述
在这里我专门给测试TextView加入了背景和字体,我们发现,在背景方面,Span只能作用于Text的绘制区域。在字体颜色方面Span是优于我们设置的字体颜色的。

   /***
* 颜色相关
* BackgroundColorSpan : 背景颜色样式
* ForegroundColorSpan : 字体颜色
*/

public void colorSpan(){
Spannable spannable = Spannable.Factory.getInstance().newSpannable(text);
BackgroundColorSpan backgroundColorSpan = new BackgroundColorSpan(Color.parseColor("#FF0000"));
spannable.setSpan(backgroundColorSpan, 0, 9, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
mTextView.setText(spannable);

Spannable spannable1 = Spannable.Factory.getInstance().newSpannable(text);
ForegroundColorSpan foregroundColorSpan = new ForegroundColorSpan(Color.parseColor("#FF0000"));
spannable1.setSpan(foregroundColorSpan, 0, 9, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
mTextView1.setText(spannable1);
}

1.4、大小位置相关

大小方面主要是RelativeSizeSpan,构造时传入一个数值来说明比较当前字体大小的变化,大于0为变大,小于0为变小
位置方面主要是上移(SuperscriptSpan),下移(SubscriptSpan),移动完成以后大小是不会变化的,上移距离为当前文本高度的一半,下一距离也是当前文本的一半。
这里写图片描述

/**
* 大小相关
* RelativeSizeSpan :显示大小
*
* 位置相关
* SuperscriptSpan :上移
* SubscriptSpan : 下移
*/

public void sizeSpan(){
Spannable spannable = Spannable.Factory.getInstance().newSpannable(text);
RelativeSizeSpan sizeSpanBig = new RelativeSizeSpan(1.4f);
RelativeSizeSpan sizeSpanSmall = new RelativeSizeSpan(0.6f);
spannable.setSpan(sizeSpanSmall, 0, 9, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
spannable.setSpan(sizeSpanBig, 11, spannable.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
mTextView.setText(spannable);

Spannable SuperscriptSpanAble = Spannable.Factory.getInstance().newSpannable(text);
SuperscriptSpan sizeSpan = new SuperscriptSpan();
SuperscriptSpanAble.setSpan(sizeSpan, 12, spannable.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
mTextView1.setText(SuperscriptSpanAble);

Spannable SubscriptSpanAble = Spannable.Factory.getInstance().newSpannable(text);
SubscriptSpan SubscriptSpan = new SubscriptSpan();
SubscriptSpanAble.setSpan(SubscriptSpan, 12, spannable.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
mTextView2.setText(SubscriptSpanAble);
}

1.5、常见样式相关

常见样式有下划线,删除线,textStyle(粗体、斜体)。
这里写图片描述

    /***
* 样式相关:
* StrikethroughSpan : 删除线
* UnderlineSpan : 下划线
*
* StyleSpan : 一般样式
*/

public void styleSpan(){
Spannable spannable = Spannable.Factory.getInstance().newSpannable(text);
StrikethroughSpan strikethroughSpan = new StrikethroughSpan();
spannable.setSpan(strikethroughSpan, 0, 9, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
mTextView.setText(spannable);

Spannable underlineSpanAble = Spannable.Factory.getInstance().newSpannable(text);
UnderlineSpan sizeSpan = new UnderlineSpan();
underlineSpanAble.setSpan(sizeSpan, 11, spannable.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
mTextView1.setText(underlineSpanAble);

Spannable styleSpan = Spannable.Factory.getInstance().newSpannable(text);
StyleSpan styleSpan_Bold = new StyleSpan(Typeface.BOLD);
StyleSpan styleSpan_Italic = new StyleSpan(Typeface.ITALIC);
styleSpan.setSpan(styleSpan_Bold, 0, 9, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
styleSpan.setSpan(styleSpan_Italic, 11, spannable.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
mTextView2.setText(styleSpan);
}

1.6、跳转相关

常见的跳转相关有,点击事件,超链接。其实超链接的实现就是点击事件,只不过点击以后由当前手机的默认浏览器去打开。
这里写图片描述

/**
* ClickableSpan : 可点击的文字
*
*/

public void clickSpan(){
Spannable spannable = Spannable.Factory.getInstance().newSpannable(text);
spannable.setSpan(new ClickableSpan() {
@Override
public void onClick(View widget) {
Toast.makeText(RichTextActivity.this, "点击测试", Toast.LENGTH_LONG).show();
}
},
9, spannable.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
mTextView.setMovementMethod(LinkMovementMethod.getInstance());
mTextView.setText(spannable);


Spannable spannableUrl = Spannable.Factory.getInstance().newSpannable(text);
URLSpan urlSpan = new URLSpan("http://blog.csdn.net/lpc_java?viewmode=list");
spannableUrl.setSpan(urlSpan, 9, spannable.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
mTextView1.setText(spannableUrl);
mTextView1.setMovementMethod(LinkMovementMethod.getInstance());

mTextView2.setVisibility(View.GONE);
}

注意:mTextView1.setMovementMethod(LinkMovementMethod.getInstance());必须设置TextView的MovementMethod才有点击效果

1.7、图片相关

在文字当中使用图片,其实这个我们可以联想一下社交软件当中的聊天表情。
这里写图片描述
在这里我们发现,是图片去替代了我们原有的文字,看客们在这里注意一下。

/**
* 图片相关
* ImageSpan
*/

public void imageSpan(){
Spannable spannableImgae = Spannable.Factory.getInstance().newSpannable(text);
Drawable image = this.getResources().getDrawable(R.mipmap.star);
image.setBounds(0,0,60,60);

ImageSpan imageSpan = new ImageSpan(image);
spannableImgae.setSpan(imageSpan, spannableImgae.length()-2, spannableImgae.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
mTextView.setText(spannableImgae);

mTextView1.setVisibility(View.GONE);
mTextView2.setVisibility(View.GONE);
}

好了基本的几种在这里都已经说完


2 、其他方式实现富文本显示

HTML,也可以实现上述的功能,就是把含有HTML标签的语句直接在TextView当中进行显示,

   public void html(){
String html = "测



"
;
mTextView.setText(Html.fromHtml(html));

String html1 = "

标题

"
;
mTextView1.setText(Html.fromHtml(html1));

String html2 = "测试文字" ;
mTextView2.setText(Html.fromHtml(html2));
}

这里写图片描述

但是TextView对HTML的支持不是很全,下面就把TextView对HTML的支持列举一下

a href=”…”> 定义链接内容
b> 定义粗体文字 b 是blod的缩写
big> 定义大字体的文字
blockquote> 引用块标签
属性:
Common – 一般属性
cite – 被引用内容的URI
br> 定义换行
cite> 表示引用的URI
dfn> 定义标签 dfn 是defining instance的缩写
div align=”…”>
em> 强调标签 em 是emphasis的缩写
font size=”…” color=”…” face=”…”>
h1>
h2>
h3>
h4>
h5>
h6>
i> 定义斜体文字
img src=”…”>
p> 段落标签,里面可以加入文字,列表,表格等
small> 定义小字体的文字
strike> 定义删除线样式的文字 不符合标准网页设计的理念,不赞成使用. strike是strikethrough的缩写
strong> 重点强调标签
sub> 下标标签 sub 是subscript的缩写
sup> 上标标签 sup 是superscript的缩写
tt> 定义monospaced字体的文字 不赞成使用. 此标签对中文没意义 tt是teletype or monospaced text style的意思
u> 定义带有下划线的文字 u是underlined text style的意思

笔者在这里把第一个 <取消啦 因为格式会乱,相信各位看客也能理解

结束语

在此 算是结束啦 在这里附上源码链接,
源码下载

参考文献
https://developer.android.com/reference/android/text/Spannable.html
https://developer.android.com/reference/android/text/style/CharacterStyle.html
https://developer.android.com/reference/android/text/style/ParagraphStyle.html
https://github.com/Manabu-GT/ExpandableTextView

http://www.jianshu.com/p/84067ad289d2
http://www.jianshu.com/p/aa53ee98d954
http://2960629.blog.51cto.com/2950629/751360
https://juejin.im/entry/5729d28f1ea49300606854c9


推荐阅读
  • 深入解析 Android 中 EditText 的 getLayoutParams 方法及其代码应用实例 ... [详细]
  • 使用 ListView 浏览安卓系统中的回收站文件 ... [详细]
  • Android 自定义 RecycleView 左滑上下分层示例代码
    为了满足项目需求,需要在多个场景中实现左滑删除功能,并且后续可能在列表项中增加其他功能。虽然网络上有很多左滑删除的示例,但大多数封装不够完善。因此,我们尝试自己封装一个更加灵活和通用的解决方案。 ... [详细]
  • 如果应用程序经常播放密集、急促而又短暂的音效(如游戏音效)那么使用MediaPlayer显得有些不太适合了。因为MediaPlayer存在如下缺点:1)延时时间较长,且资源占用率高 ... [详细]
  • 实验九:使用SharedPreferences存储简单数据
    本实验旨在帮助学生理解和掌握使用SharedPreferences存储和读取简单数据的方法,包括程序参数和用户选项。 ... [详细]
  • 本文介绍了一种自定义的Android圆形进度条视图,支持在进度条上显示数字,并在圆心位置展示文字内容。通过自定义绘图和组件组合的方式实现,详细展示了自定义View的开发流程和关键技术点。示例代码和效果展示将在文章末尾提供。 ... [详细]
  • 【问题】在Android开发中,当为EditText添加TextWatcher并实现onTextChanged方法时,会遇到一个问题:即使只对EditText进行一次修改(例如使用删除键删除一个字符),该方法也会被频繁触发。这不仅影响性能,还可能导致逻辑错误。本文将探讨这一问题的原因,并提供有效的解决方案,包括使用Handler或计时器来限制方法的调用频率,以及通过自定义TextWatcher来优化事件处理,从而提高应用的稳定性和用户体验。 ... [详细]
  • 在处理 XML 数据时,如果需要解析 `` 标签的内容,可以采用 Pull 解析方法。Pull 解析是一种高效的 XML 解析方式,适用于流式数据处理。具体实现中,可以通过 Java 的 `XmlPullParser` 或其他类似的库来逐步读取和解析 XML 文档中的 `` 元素。这样不仅能够提高解析效率,还能减少内存占用。本文将详细介绍如何使用 Pull 解析方法来提取 `` 标签的内容,并提供一个示例代码,帮助开发者快速解决问题。 ... [详细]
  • ButterKnife 是一款用于 Android 开发的注解库,主要用于简化视图和事件绑定。本文详细介绍了 ButterKnife 的基础用法,包括如何通过注解实现字段和方法的绑定,以及在实际项目中的应用示例。此外,文章还提到了截至 2016 年 4 月 29 日,ButterKnife 的最新版本为 8.0.1,为开发者提供了最新的功能和性能优化。 ... [详细]
  • 深入解析 Lifecycle 的实现原理
    本文将详细介绍 Android Jetpack 中 Lifecycle 组件的实现原理,帮助开发者更好地理解和使用 Lifecycle,避免常见的内存泄漏问题。 ... [详细]
  • 解决Bootstrap DataTable Ajax请求重复问题
    在最近的一个项目中,我们使用了JQuery DataTable进行数据展示,虽然使用起来非常方便,但在测试过程中发现了一个问题:当查询条件改变时,有时查询结果的数据不正确。通过FireBug调试发现,点击搜索按钮时,会发送两次Ajax请求,一次是原条件的请求,一次是新条件的请求。 ... [详细]
  • 在《Cocos2d-x学习笔记:基础概念解析与内存管理机制深入探讨》中,详细介绍了Cocos2d-x的基础概念,并深入分析了其内存管理机制。特别是针对Boost库引入的智能指针管理方法进行了详细的讲解,例如在处理鱼的运动过程中,可以通过编写自定义函数来动态计算角度变化,利用CallFunc回调机制实现高效的游戏逻辑控制。此外,文章还探讨了如何通过智能指针优化资源管理和避免内存泄漏,为开发者提供了实用的编程技巧和最佳实践。 ... [详细]
  • 在Android平台中,播放音频的采样率通常固定为44.1kHz,而录音的采样率则固定为8kHz。为了确保音频设备的正常工作,底层驱动必须预先设定这些固定的采样率。当上层应用提供的采样率与这些预设值不匹配时,需要通过重采样(resample)技术来调整采样率,以保证音频数据的正确处理和传输。本文将详细探讨FFMpeg在音频处理中的基础理论及重采样技术的应用。 ... [详细]
  • Web开发框架概览:Java与JavaScript技术及框架综述
    Web开发涉及服务器端和客户端的协同工作。在服务器端,Java是一种优秀的编程语言,适用于构建各种功能模块,如通过Servlet实现特定服务。客户端则主要依赖HTML进行内容展示,同时借助JavaScript增强交互性和动态效果。此外,现代Web开发还广泛使用各种框架和库,如Spring Boot、React和Vue.js,以提高开发效率和应用性能。 ... [详细]
  • 在Android开发中,实现多点触控功能需要使用`OnTouchListener`监听器来捕获触摸事件,并在`onTouch`方法中进行详细的事件处理。为了优化多点触控的交互体验,开发者可以通过识别不同的触摸手势(如缩放、旋转等)并进行相应的逻辑处理。此外,还可以结合`MotionEvent`类提供的方法,如`getPointerCount()`和`getPointerId()`,来精确控制每个触点的行为,从而提升用户操作的流畅性和响应性。 ... [详细]
author-avatar
mobiledu2502853397
这个家伙很懒,什么也没留下!
Tags | 热门标签
RankList | 热门文章
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有