在项目中有一个小功能需要实现,就是对多行文本进行排版布局,每一行的内容又分为两部分,左边为标题,右边为描述,左边内容长度不确定,右边的内容需要对齐,如有换行也需要对齐右边的文本。

效果图

效果图如下图所示:

可以看到内容分成了两部分,左边的颜色与右边不一致,右边的描述文案统一对齐。

实现方案

以上功能,由于输入内容输入行数不确定,并且左边的文案长度也不确定,因此不能直接在布局中实现,基于此这里主要实现了以下6种方式

方案1

采用自定义控件的方式,继承TextView,重新onDraw函数,实现如下:


/*** 计算出左边最长的显示字符串maxLeftWidth,之后draw每一行字符,右边的描述从maxLeftWidth开始draw* 当一行显示不完全时,折行并且空出maxLeftWidth的空格长度*/
public class TypographyView1 extends TextView {private Paint leftPaint = new Paint();private Paint rightPaint = new Paint();private int fullWidth;private float textSize;private JSONArray array;private int middlePadding = 0;float maxLeftWidth = 0;int itemSize = 0;public TypographyView1(Context context) {super(context);init();}public TypographyView1(Context context, AttributeSet attrs) {super(context, attrs);init();}public TypographyView1(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init();}private void init() {textSize = getResources().getDimensionPixelSize(R.dimen.text_size_13);leftPaint.setAntiAlias(true);leftPaint.setTextSize(textSize);leftPaint.setColor(getResources().getColor(R.color.color_black_999999));rightPaint.setAntiAlias(true);rightPaint.setTextSize(textSize);rightPaint.setColor(getResources().getColor(R.color.color_black));middlePadding = getResources().getDimensionPixelSize(R.dimen.padding_value);}@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);fullWidth = getWidth();// 整个textView的宽度}public void setText(JSONArray array) {this.array = array;if (array != null) {try {int size = itemSize = array.length();for (int i = 0; i < size; ++i) {JSONArray o = (JSONArray) array.get(i);String key = o.getString(0);String value = o.getString(1);if (TextUtils.isEmpty(key) || TextUtils.isEmpty(value)) {itemSize--;continue;}float curWidth = leftPaint.measureText(key);if (curWidth > maxLeftWidth) {maxLeftWidth = curWidth;}}maxLeftWidth = maxLeftWidth + middlePadding;invalidate();} catch (Exception e) {}}}boolean setHeight = false;@Overrideprotected void onDraw(Canvas canvas) {if (array == null) {return;}int lineCount = 0;try {JSONArray item;float offsetY;for (int i = 0; i < itemSize; ++i) {item = (JSONArray) array.get(i);offsetY = (lineCount + 1) * textSize;canvas.drawText(item.getString(0), 0, offsetY, leftPaint);String value = item.getString(1);float valueWidth = rightPaint.measureText(value);if (valueWidth > fullWidth - maxLeftWidth) {// 一行显示不完char[] textCharArray = value.toCharArray();float charWidth;float drawWidth = maxLeftWidth;for (int j = 0; j < textCharArray.length; j++) {charWidth = rightPaint.measureText(textCharArray, j, 1);if (fullWidth - drawWidth < charWidth) {lineCount++;drawWidth = maxLeftWidth;offsetY += textSize;}canvas.drawText(textCharArray, j, 1, drawWidth, offsetY, rightPaint);drawWidth += charWidth;}} else {canvas.drawText(value, maxLeftWidth, offsetY, rightPaint);}lineCount += 2;}if (!setHeight) {setHeight((lineCount + 1) * (int) textSize);setHeight = true;}} catch (JSONException e) {e.printStackTrace();}}
}

添加了setText(JSONArray array)作为数据输入,并且在这里面测量了左边title的最大宽度,之后调用invalidate触发重绘,在onSizeChanged获取整个控件的宽度,重绘会调用onDraw函数,这里不需要调用super函数,TextView的onDraw函数做了非常多的操作,解析传入的数据,分别一行一行调用canvas来进行drawText操作,当绘制描述时,先计算宽度,如果超过剩余控件说明需要换行,最后调用setHeight设置高度,这个加一个判断条件,因为会触发requestLayout()进行重新布局和invalidate()进行重绘,如果不加判断会一直重绘。

方案2

方式2与方式1差不多,不同为所有计算都在onDraw函数中:

/*** 该方式与方式1很类似,只是所有的计算都放在了onDraw方法中。*/
public class TypographyView2 extends TextView {private Paint paint1 = new Paint();private Paint paint2 = new Paint();private int middlePadding = 0;int width;private float textSize;private JSONArray array;public TypographyView2(Context context) {super(context);init();}public TypographyView2(Context context, AttributeSet attrs) {super(context, attrs);init();}public TypographyView2(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init();}private void init() {textSize = getResources().getDimensionPixelSize(R.dimen.text_size_13);paint1.setAntiAlias(true);paint1.setTextSize(textSize);paint1.setColor(getResources().getColor(R.color.color_black_999999));paint2.setAntiAlias(true);paint2.setTextSize(textSize);paint2.setColor(getResources().getColor(R.color.color_black));middlePadding = getResources().getDimensionPixelSize(R.dimen.padding_value);}@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);width = getWidth();// 整个textView的宽度}public void setText(JSONArray array) {this.array = array;if (array != null) {invalidate();}}boolean setHeight = false;@Overrideprotected void onDraw(Canvas canvas) {// super.onDraw(canvas);int lineCount = 0;int size = array.length();float maxLeftWidth = 0;float drawWidth = 0;try {for (int i = 0; i < size; ++i) {JSONArray o = (JSONArray) array.get(i);String key = o.getString(0);float v = paint1.measureText(key);if (v > maxLeftWidth) {maxLeftWidth = v;}}maxLeftWidth = maxLeftWidth + middlePadding;for (int i = 0; i < size; ++i) {JSONArray o = (JSONArray) array.get(i);String key = o.getString(0);canvas.drawText(key, 0, (lineCount + 1) * textSize, paint1);String value = o.getString(1);char[] textCharArray = value.toCharArray();float charWidth;drawWidth = maxLeftWidth;for (int j = 0; j < textCharArray.length; j++) {charWidth = paint1.measureText(textCharArray, j, 1);if (width - drawWidth < charWidth) {lineCount++;drawWidth = maxLeftWidth;}canvas.drawText(textCharArray, j, 1, drawWidth, (lineCount + 1) * textSize, paint2);drawWidth += charWidth;}lineCount += 2;}if (!setHeight) {setHeight((lineCount + 1) * (int) textSize + 5);setHeight = true;}} catch (JSONException e) {e.printStackTrace();}}
}

该方案的实现是不太好的,方案1也是在此基础上进行调整的,在这里放出来只是为了说明,所有的计算不要全部放在onDraw里面,因为该方法可能会反复调用多次,这样就降低了性能。

方案3

将数据源拼接成SpannableString,重写onDraw函数,根据内容draw每一个字符:

/*** 该方法,是需要显示的内容先拼接成SpannableString,在onDraw方法中获取所有的char字符,一个一个比较* 当为分号是,表示为key与value的分隔符。*/
public class TypographyView3 extends TextView {private Paint leftPaint = new Paint();private Paint rightPaint = new Paint();int width;private String text;private float textSize;float maxLeftWidth = 0;private int middlePadding = 0;public TypographyView3(Context context) {super(context);init();}public TypographyView3(Context context, AttributeSet attrs) {super(context, attrs);init();}public TypographyView3(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init();}private void init() {textSize = getResources().getDimensionPixelSize(R.dimen.text_size_13);textSize = getResources().getDimensionPixelSize(R.dimen.text_size_13);leftPaint.setAntiAlias(true);leftPaint.setTextSize(textSize);leftPaint.setColor(getResources().getColor(R.color.color_black_999999));rightPaint.setAntiAlias(true);rightPaint.setTextSize(textSize);rightPaint.setColor(getResources().getColor(R.color.color_black));middlePadding = getResources().getDimensionPixelSize(R.dimen.padding_value);}@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);width = getWidth();// 整个textView的宽度}public void setText(JSONArray data) {if (data == null) {return;}try {int size = data.length();for (int i = 0; i < size; ++i) {JSONArray o = (JSONArray) data.get(i);String key = o.getString(0);float v = leftPaint.measureText(key);if (v > maxLeftWidth) {maxLeftWidth = v;}}maxLeftWidth += middlePadding;SpannableStringBuilder ssb = new SpannableStringBuilder();for (int i = 0; i < size; ++i) {addItem((JSONArray) data.get(i), ssb, i != 0);}setText(ssb, BufferType.SPANNABLE);} catch (Exception e) {}}private void addItem(JSONArray item, SpannableStringBuilder ssb, boolean breakLine) {try {if (item == null || item.length() == 0) {return;}String key = item.getString(0);String value = (item.length() >= 2) ? item.getString(1) : "";if (TextUtils.isEmpty(key) && TextUtils.isEmpty(value)) {return;}if (breakLine) {// 换行ssb.append("\r\n");ssb.append("\r\n");}SpannableString span = new SpannableString(key);//            span.setSpan(new ForegroundColorSpan(getResources().getColor(R.color.colorAccent)), 0, key// .length(),//                    Spanned.SPAN_INCLUSIVE_EXCLUSIVE);ssb.append(span);ssb.append(value);} catch (JSONException e) {e.printStackTrace();}}@Overrideprotected void onDraw(Canvas canvas) {// super.onDraw(canvas);int lineCount = 0;text = this.getText().toString();if (text == null)return;char[] textCharArray = text.toCharArray();// 已绘的宽度float drawWidth = 0;float charWidth;Paint paint = leftPaint;for (int i = 0; i < textCharArray.length; i++) {charWidth = leftPaint.measureText(textCharArray, i, 1);if (textCharArray[i] == '\n') {lineCount++;drawWidth = 0;paint = leftPaint;continue;}if (width - drawWidth < charWidth) {lineCount++;drawWidth = maxLeftWidth;}if (i > 1 && textCharArray[i - 1] == ':') {drawWidth = maxLeftWidth;paint = rightPaint;}canvas.drawText(textCharArray, i, 1, drawWidth, (lineCount + 1) * textSize, paint);drawWidth += charWidth;}//may be need set height//setHeight((lineCount + 1) * (int) textSize + 5);}
}

这里先计算左边title的最大宽度,同时将所有的数据拼接成一个SpannableStringBuilder,调用setText函数会触发重绘,在onDraw函数中进行处理,由于未重新super函数,因此SpannableString的setSpan函数失效,该方案主要根据分隔符来进行分割,因此分隔符需要唯一。

方案4

采用GridLayout方式实现,但是原始控件有展示问题,因此对此进行了修改:

public class Typography4Activity extends BaseActivity {public static void start(Context context) {Intent intent = new Intent();intent.setClass(context, Typography4Activity.class);context.startActivity(intent);}private LinearLayout root;private Paint leftPaint = new Paint();private float textSize;private float maxLeftWidth;private int middlePadding = 0;private float maxRightWidth;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);root = (LinearLayout) LayoutInflater.from(this).inflate(R.layout.activity_typography4, null);setContentView(root);initPaint();findViews();loadData();}private void initPaint() {textSize = getResources().getDimensionPixelSize(R.dimen.text_size_13);leftPaint.setAntiAlias(true);leftPaint.setTextSize(textSize);leftPaint.setColor(getResources().getColor(R.color.color_black_999999));middlePadding = getResources().getDimensionPixelSize(R.dimen.padding_value);}private void findViews() {}private void loadData() {addGridLayout(DataSource.getArray());TextView view = new TextView(this);view.setText("修改后的实现");view.setGravity(Gravity.CENTER);view.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 160));root.addView(view);addModifyGridLayout(DataSource.getArray());}private void addGridLayout(JSONArray data) {try {GridLayout layout = createGridLayout();int size = data.length();for (int i = 0; i < size; ++i) {JSONArray item = (JSONArray) data.get(i);String key = item.getString(0);String value = (item.length() >= 2) ? item.getString(1) : "";GridLayout.Spec row = GridLayout.spec(i);GridLayout.Spec col1 = GridLayout.spec(0);GridLayout.Spec col2 = GridLayout.spec(1);GridLayout.LayoutParams params = new GridLayout.LayoutParams(row, col1);TextView title = getLeftTextView(key);layout.addView(title, params);params = new GridLayout.LayoutParams(row, col2);TextView desc = getRightTextView(value);layout.addView(desc, params);}root.addView(layout);} catch (Exception e) {}}@NonNullprivate TextView getRightTextView(String value) {TextView desc = new TextView(this);desc.setTextSize(13);desc.setTextColor(getResources().getColor(R.color.black));desc.setText(value);return desc;}@NonNullprivate TextView getLeftTextView(String key) {TextView title = new TextView(this);title.setText(key);title.setPadding(0, middlePadding, middlePadding, 0);title.setTextColor(getResources().getColor(R.color.color_black_999999));title.setTextSize(13);return title;}private void addModifyGridLayout(JSONArray data) {try {calculateLeftMaxWidth(data);GridLayout layout = createGridLayout();int size = data.length();for (int i = 0; i < size; ++i) {JSONArray item = (JSONArray) data.get(i);GridLayout.Spec row = GridLayout.spec(i);String key = item.getString(0);GridLayout.Spec col1 = GridLayout.spec(0);GridLayout.LayoutParams params = new GridLayout.LayoutParams(row, col1);TextView title = getLeftTextView(key);layout.addView(title, params);String value = (item.length() >= 2) ? item.getString(1) : "";GridLayout.Spec col2 = GridLayout.spec(1);params = new GridLayout.LayoutParams(row, col2);TextView desc = getRightTextView(value);params.width = (int) maxRightWidth;params.height = ViewGroup.LayoutParams.WRAP_CONTENT;layout.addView(desc, params);}root.addView(layout);} catch (Exception e) {}}private void calculateLeftMaxWidth(JSONArray data) {try {DisplayUtil.init(this);// 这个可以在应用程序起来的时候initint size = data.length();for (int i = 0; i < size; ++i) {JSONArray o = (JSONArray) data.get(i);String key = o.getString(0);String value = o.getString(1);if (TextUtils.isEmpty(key) || TextUtils.isEmpty(value)) {continue;}float curWidth = leftPaint.measureText(key);if (curWidth > maxLeftWidth) {maxLeftWidth = curWidth;}}maxLeftWidth = maxLeftWidth + middlePadding;maxRightWidth = DisplayUtil.screenWidth - DisplayUtil.dp2px(this, 32 + 10) - maxLeftWidth;} catch (Exception e) {}}private GridLayout createGridLayout() {GridLayout layout = new GridLayout(this);layout.setColumnCount(2);//layout.setRowCount(5);layout.setOrientation(GridLayout.HORIZONTAL);return layout;}
}

如果直接创建一个GridLayout,里面添加每一项,如果描述过长都导致显示不全,这个是系统的一个bug,计算的宽度有问题,因此需要对此方案进行更改。
       更改方式为先计算左边占用的最大宽度,在添加右边的项时,设置布局参数控制最大的长度。

方案5

采用每一行一个布局,手动一行一行进行添加:

public class Typography5Activity extends BaseActivity {public static void start(Context context) {Intent intent = new Intent();intent.setClass(context, Typography5Activity.class);context.startActivity(intent);}private LinearLayout root;private Paint leftPaint = new Paint();private float textSize;private float maxLeftWidth;private int middlePadding = 0;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);root = (LinearLayout) LayoutInflater.from(this).inflate(R.layout.activity_typography5, null);setContentView(root);initPaint();loadData();}private void initPaint() {textSize = getResources().getDimensionPixelSize(R.dimen.text_size_13);leftPaint.setAntiAlias(true);leftPaint.setTextSize(textSize);leftPaint.setColor(getResources().getColor(R.color.color_black_999999));middlePadding = getResources().getDimensionPixelSize(R.dimen.padding_value);}private void loadData() {JSONArray array = DataSource.getArray();calculateLeftMaxWidth(array);if (array != null) {try {int size = array.length();for (int i = 0; i < size; ++i) {JSONArray o = (JSONArray) array.get(i);String key = o.getString(0);String value = o.getString(1);addItem(key, value);}} catch (Exception e) {}}}private void calculateLeftMaxWidth(JSONArray data) {try {int size = data.length();for (int i = 0; i < size; ++i) {JSONArray o = (JSONArray) data.get(i);String key = o.getString(0);String value = o.getString(1);if (TextUtils.isEmpty(key) || TextUtils.isEmpty(value)) {continue;}float curWidth = leftPaint.measureText(key);if (curWidth > maxLeftWidth) {maxLeftWidth = curWidth;}}maxLeftWidth = maxLeftWidth + middlePadding;} catch (Exception e) {}}private void addItem(String key, String value) {LinearLayout layout = getItemLayout();TextView left = (TextView) layout.findViewById(R.id.left);LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.WRAP_CONTENT);params.width = (int) maxLeftWidth;left.setLayoutParams(params);left.setText(key);TextView right = (TextView) layout.findViewById(R.id.right);right.setText(value);root.addView(layout);}private LinearLayout getItemLayout() {LinearLayout layout = (LinearLayout) LayoutInflater.from(this).inflate(R.layout.compose_item_layout, null);return layout;}
}

改方案也需要先计算左边的最大占用宽度,来设置右边占用的大小,每一项的布局如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="horizontal"android:paddingTop="@dimen/text_padding_10"tools:context=".activity.Typography1Activity"><TextView
        android:id="@+id/left"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginRight="@dimen/text_padding_10"android:textColor="@color/color_black_999999"android:textSize="@dimen/text_size_13"/><TextView
        android:id="@+id/right"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:textColor="@color/black"android:textSize="@dimen/text_size_13"/></LinearLayout>

每一行有两个TextView,左边宽度为自适应,右边占据剩下左右的位置,在计算出左边最大宽度后,重新设置左边每一个TextView占用的宽度。

方案6

方式与1差不多,但是不在继承TextView,而是直接继承View:

public class TypographyView4 extends View {private Paint leftPaint = new Paint();private Paint rightPaint = new Paint();private int fullWidth;private float textSize;private JSONArray array;private int middlePadding = 0;float maxLeftWidth = 0;int itemSize = 0;public TypographyView4(Context context) {super(context);init();}public TypographyView4(Context context, AttributeSet attrs) {super(context, attrs);init();}public TypographyView4(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init();}private void init() {textSize = getResources().getDimensionPixelSize(R.dimen.text_size_13);leftPaint.setAntiAlias(true);leftPaint.setTextSize(textSize);leftPaint.setColor(getResources().getColor(R.color.color_black_999999));rightPaint.setAntiAlias(true);rightPaint.setTextSize(textSize);rightPaint.setColor(getResources().getColor(R.color.color_black));middlePadding = getResources().getDimensionPixelSize(R.dimen.padding_value);}@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);fullWidth = getWidth();// 整个textView的宽度}public void setText(JSONArray array) {this.array = array;if (array != null) {try {int size = itemSize = array.length();for (int i = 0; i < size; ++i) {JSONArray o = (JSONArray) array.get(i);String key = o.getString(0);String value = o.getString(1);if (TextUtils.isEmpty(key) || TextUtils.isEmpty(value)) {itemSize--;continue;}float curWidth = leftPaint.measureText(key);if (curWidth > maxLeftWidth) {maxLeftWidth = curWidth;}}maxLeftWidth = maxLeftWidth + middlePadding;invalidate();} catch (Exception e) {}}}@Overrideprotected void onDraw(Canvas canvas) {if (array == null) {return;}int lineCount = 0;try {JSONArray item;float offsetY;for (int i = 0; i < itemSize; ++i) {item = (JSONArray) array.get(i);offsetY = (lineCount + 1) * textSize;canvas.drawText(item.getString(0), 0, offsetY, leftPaint);String value = item.getString(1);float valueWidth = rightPaint.measureText(value);if (valueWidth > fullWidth - maxLeftWidth) {// 一行显示不完char[] textCharArray = value.toCharArray();float charWidth;float drawWidth = maxLeftWidth;for (int j = 0; j < textCharArray.length; j++) {charWidth = rightPaint.measureText(textCharArray, j, 1);if (fullWidth - drawWidth < charWidth) {lineCount++;drawWidth = maxLeftWidth;offsetY += textSize;}canvas.drawText(textCharArray, j, 1, drawWidth, offsetY, rightPaint);drawWidth += charWidth;}} else {canvas.drawText(value, maxLeftWidth, offsetY, rightPaint);}lineCount += 2;}} catch (JSONException e) {e.printStackTrace();}}
}

该方案主要继承自View,不再继承TextView,由于在在上述方案中不在调用super,因此TextView已经退化为一个View,因此直接继承View。

总结

因为左边的宽度不确定,因此所有的方案都进行了同样的一个操作,就是测量了左边显示的最大宽度,后续的操作再根据该宽度进行调整。上述的方案中1,2,3,6都只需用一个View来进行显示,4,5都需要多个View进行显示。
       完整的代码可以在查看链接上进行查看。

Android文本排版实现相关推荐

  1. 文字如何实现完美UI?文本排版设计告诉你

    2019独角兽企业重金招聘Python工程师标准>>> 一部手机,电量充足,网络通畅,就足以让我们打发一天的时光,尽情沉浸在手机时代的缤纷世界里.这个信息资源无穷尽的手机网络世界,是 ...

  2. android去广告软件下载,Android文本编辑器(QuickEdit)V1.1.4 精简去广告版

    Android文本编辑器(QuickEdit)是Android上的高效,稳定和全功能的文本编辑器.QuickEdit文本编辑器包含了大量性能和用户体验方面的优化,它的速度和输入反馈更加优越.你可以使用 ...

  3. android 文本后图标_如何在Android中更改文本,图标等的大小

    android 文本后图标 Let's face it: no matter how good the screens are on our phones and tablets, the text ...

  4. Android文本输入框EditText方法说明和属性

    1.EditText输入的文字为密码形式的设置 (1)通过.xml里设置: 把该EditText设为:android:password="true" // 以".&quo ...

  5. java做安卓文本编辑器,android文本编辑器

    [实例简介] android 文本编辑器 源码,比较简单的,可以参考一下. [实例截图] [核心代码] da76c95e-2751-4a37-9ba2-b69647edd323 └── droid-w ...

  6. Web网页设计之HTML_2. HTML元素 简单文本排版

    上一节我们认识了Web,认识了HTML,还介绍了一个工具WebStorm,这一节,我们就用这个工具学习一下HTML中的一些常用标签元素. 一.HTML基本结构 首先我们来说一下这个HTML的基本结构啊 ...

  7. 超详细:SwiftUI文本排版布局和动态字体缩放的奥秘

    功能需求 如果每个App都是一个有趣的灵魂,那么每个灵魂自然也少不了一张美丽的皮肤. SwiftUI使得App界面构建如此的简单,而App界面中怎能少得了文本的显示呢? 那么,我们能否充分利用Swif ...

  8. android 文本框(textview)左右滑动

    实现android文本框的触摸左右滑动,不需要自定自定义什么的,直接textview就自带了,如下(以左右滑动为列子): 布局文件中定义(事实上这个布局里只配置maxLines 就可以了): < ...

  9. Android 文本阅读器源代码 学习

    1 来源 http://www.apkbus.com/android-83021-1-1.html 从这个地方下载了一个android 文本阅读器,比较简单,稍微分析以下. 2 代码不是很难,记录以下 ...

最新文章

  1. mysql数据库主从操作记录
  2. Windows进程与线程学习笔记(七)—— 时间片管理
  3. 绕过安卓SSL验证证书的四种方式
  4. 生成树的计数 Matrix-Tree(矩阵树)定理
  5. 腾讯 AI Lab 正式开源PocketFlow自动化深度学习模型压缩与加速框架
  6. 记录一次参加D2前端技术论坛的杭州之行
  7. 软件工程结对项目:四则运算web
  8. html5 过渡时间,CSS3 对过渡(transition)进行调速以及延时
  9. CSS3+JS实现静态圆形进度条【清晰、易懂】
  10. Keil中如何生成bin文件
  11. WPS Office 2009 个人免费正版下载 【转载】
  12. html5好看的注册页面设计,美观大气注册登录页面模板html源码
  13. “双一流”霸气官宣:博士生,涨薪!
  14. 基于Android Studio开发的笔记APP
  15. 【原生js】动态添加class
  16. 【企业网盘】公有云和私有云的9大差异 | 燕麦企业云盘(OATOS企业网盘)
  17. mingw32-make.exe缺少的方法
  18. 修理机器人基维斯_《魔兽世界》魔兽世界修理机器人心得
  19. 2022秋招系列------海康威视
  20. 计算机无法播放视频,电脑播放器无法播放视频怎么处理

热门文章

  1. 医疗新媒体之微信营销策略
  2. ORY/kratos-01-快速入门
  3. 计算机乐谱制作师专业,计算机乐谱制作师: 基础知识
  4. 安卓游戏录屏v2.5.4会员版
  5. 软件开发实习个人总结
  6. vue打包后static中的文件未打包进去
  7. 如何在 Flutter 中添加 ListTile:带示例的教程
  8. MacOS苹果电脑进入恢复模式
  9. ZooKeeper如何模拟会话失效(Session Expired)
  10. 如何在家远程控制公司电脑使办公更加方便呢?