今天在做項(xiàng)目的時(shí)候籽御,接口返回的信息是html格式的绰沥,一開始我是用textView.setText(Html.fromHtml("html標(biāo)簽字符串",null,null));但是發(fā)現(xiàn)html標(biāo)簽里有img標(biāo)簽篱蝇,里面還有一個(gè)圖片的鏈接url,如下所示:
<img title="058B4D41236B9980FC1C07C9EC49872E.png" src="http://www.hbxyjob.cn/cmsfiles/1/image/public/201708/20170824093509_2avfad9vwc.png"/>
尼瑪零截,這怎么顯示呢秃臣?于是在網(wǎng)上找了很久資料涧衙,改了一下代碼哪工,實(shí)現(xiàn)的效果如下:
1雁比、思路分析
主要是用Html.ImageGetter來實(shí)現(xiàn)
接口返回的html字段中撤嫩,有可能包含多個(gè)網(wǎng)絡(luò)圖片的地址序攘,這時(shí)候需要下載圖片到本地。
第一次顯示的時(shí)候只是把文字部分加載出來丈牢,等到圖片加載完成的時(shí)候瞄沙,再一次賦值給Textview就實(shí)現(xiàn)了上面動(dòng)圖的效果距境。
2肮疗、DownLoadHtmlImageUtils 圖片下載工具類
/**
* 項(xiàng)目名:xyjyyth
* 包名: com.tecsun.tsb.utils
* 文件名:DownLoadHtmlImageUtils
* 創(chuàng)建者:ZhuiMengXiaoLe
* 日期: 2017/10/31 18:59
* 描述: 下載Html標(biāo)簽里面的圖片
*/
public class DownLoadHtmlImageUtils {
public volatile boolean isCancle = false;
// Init Hander
EventHandler mHandler = new EventHandler(this);
/**
* DownLoad the file that must have a url
*
* @param url The http url
* @param savePath The save path
*/
public void download(final String url, final String savePath) {
Log.i("DEBUG", url+" Start!");
new Thread(new Runnable() {
public void run() {
try {
Log.i("DEBUG", url+" Start !!!!");
sendMessage(FILE_DOWNLOAD_CONNECT);
URL sourceUrl = new URL(url);
URLConnection conn = sourceUrl.openConnection();
InputStream inputStream = conn.getInputStream();
int fileSize = conn.getContentLength();
File savefile = new File(savePath);
if (savefile.exists()) {
savefile.delete();
}
savefile.createNewFile();
FileOutputStream outputStream = new FileOutputStream(savePath);
byte[] buffer = new byte[1024];
int readCount = 0;
int readNum = 0;
int prevPercent = 0;
while ((readNum = inputStream.read(buffer)) != -1) {
if (readNum > -1) {
readCount = readCount + readNum;
outputStream.write(buffer, 0, readNum);
int percent = (readCount * 100 / fileSize);
if (percent > prevPercent) {
// send the progress
sendMessage(FILE_DOWNLOAD_UPDATE, percent, readCount);
prevPercent = percent;
}
if (isCancle) {
outputStream.close();
sendMessage(FILE_DOWNLOAD_ERROR, new Exception("Stop"));
break;
}
}
}
outputStream.close();
if (!isCancle) {
sendMessage(FILE_DOWNLOAD_COMPLETE, url);
}
} catch (Exception e) {
sendMessage(FILE_DOWNLOAD_ERROR, e);
// Log.e("MyError", e.toString());
}
}
}).start();
}
/**
* send message to handler
*
* @param what handler what
* @param obj handler obj
*/
private void sendMessage(int what, Object obj) {
// init the handler message
Message msg = mHandler.obtainMessage(what, obj);
// send message
mHandler.sendMessage(msg);
}
private void sendMessage(int what) {
Message msg = mHandler.obtainMessage(what);
mHandler.sendMessage(msg);
}
private void sendMessage(int what, int arg1, int arg2) {
Message msg = mHandler.obtainMessage(what, arg1, arg2);
mHandler.sendMessage(msg);
}
public void setCancle() {
this.isCancle = true;
Log.v("setCancle", String.valueOf(isCancle));
}
private static final int FILE_DOWNLOAD_CONNECT = 0;
private static final int FILE_DOWNLOAD_UPDATE = 1;
private static final int FILE_DOWNLOAD_COMPLETE = 2;
private static final int FILE_DOWNLOAD_ERROR = -1;
// defined the handler
private class EventHandler extends Handler {
private final DownLoadHtmlImageUtils mManager;
public EventHandler(DownLoadHtmlImageUtils manager) {
mManager = manager;
}
// do the receive message
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case FILE_DOWNLOAD_CONNECT:
if (mOnDownloadListener != null)
mOnDownloadListener.onDownloadConnect(mManager);
break;
case FILE_DOWNLOAD_UPDATE:
if (mOnDownloadListener != null)
mOnDownloadListener.onDownloadUpdate(mManager, msg.arg1);
break;
case FILE_DOWNLOAD_COMPLETE:
if (mOnDownloadListener != null)
mOnDownloadListener.onDownloadComplete(mManager, msg.obj);
break;
case FILE_DOWNLOAD_ERROR:
if (mOnDownloadListener != null)
mOnDownloadListener.onDownloadError(mManager, (Exception) msg.obj);
break;
default:
break;
}
}
}
// defined connection listener
private OnDownloadListener mOnDownloadListener;
public interface OnDownloadListener {
void onDownloadConnect(DownLoadHtmlImageUtils manager);
void onDownloadUpdate(DownLoadHtmlImageUtils manager, int percent);
void onDownloadComplete(DownLoadHtmlImageUtils manager, Object result);
void onDownloadError(DownLoadHtmlImageUtils manager, Exception e);
}
public void setOnDownloadListener(OnDownloadListener listener) {
mOnDownloadListener = listener;
}
}
3钾怔、核心代碼1分析:設(shè)置TextView可點(diǎn)擊跳轉(zhuǎn)Html里面的鏈接
//保存文件路徑
private final String path = Environment.getExternalStorageDirectory().getAbsolutePath()+"/htmlimg/";
//設(shè)置鏈接中標(biāo)簽是可以點(diǎn)擊并且可以跳轉(zhuǎn)到瀏覽器打開的
tvJobDes.setClickable(true);
tvJobDes.setMovementMethod(LinkMovementMethod.getInstance());
//整個(gè)TextView居中顯示
// tvJobDes.setGravity(Gravity.CENTER_HORIZONTAL);
4宗侦、核心代碼2分析:第一次賦值給 TextView,同時(shí)開始下載圖片
private void setData() {
//初始化下載類
downLoadUtils=new DownLoadHtmlImageUtils();
//設(shè)置下載類監(jiān)聽事件
downLoadUtils.setOnDownloadListener(onDownloadListener);
//給Textview賦值
tvJobDes.setText(Html.fromHtml(mFvalue,imageGetter,null));
}
Drawable drawable = null;
Bitmap bitmap = null;
Html.ImageGetter imageGetter = new Html.ImageGetter() {
public Drawable getDrawable(String source) {
String fileString=path+String.valueOf(source.hashCode());
Log.i("DEBUG", fileString+"");
Log.i("DEBUG", source+"");
if (!new File(path).exists()){
new File(path).mkdirs();
LogUtils.d(TAG,"創(chuàng)建文件夾成功========");
}
//判斷SD卡里面是否存在圖片文件
if (new File(fileString).exists()) {
Log.i("DEBUG", fileString+" eixts");
//獲取本地文件返回Drawable
bitmap = BitmapFactory.decodeFile(fileString);
drawable = new BitmapDrawable(bitmap);
// drawable=Drawable.createFromPath(fileString);
//設(shè)置圖片邊界
if (drawable != null){
drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
return drawable;
}
return null;
}else {
Log.i("DEBUG", fileString+" Do not eixts");
//啟動(dòng)新線程下載
downLoadUtils.download(source, path+String.valueOf(source.hashCode()));
return drawable;
}
};
};
5姑裂、核心代碼3分析:等待圖片下載完成的時(shí)候,再一次賦值給TextView
DownLoadHtmlImageUtils.OnDownloadListener onDownloadListener=new DownLoadHtmlImageUtils.OnDownloadListener() {
//下載進(jìn)度
public void onDownloadUpdate(DownLoadHtmlImageUtils manager, int percent) {
// TODO Auto-generated method stub
Log.i("DEBUG", percent+"");
}
//下載失敗
public void onDownloadError(DownLoadHtmlImageUtils manager, Exception e) {
// TODO Auto-generated method stub
}
//開始下載
public void onDownloadConnect(DownLoadHtmlImageUtils manager) {
// TODO Auto-generated method stub
Log.i("DEBUG", "Start //////");
}
//完成下載
public void onDownloadComplete(DownLoadHtmlImageUtils manager, Object result) {
// TODO Auto-generated method stub
Log.i("DEBUG", result.toString());
//替換sTExt的值舶斧,就是把圖片的網(wǎng)絡(luò)路徑換成本地SD卡圖片路徑(最早想法茴厉,可以不需要這樣做了)
//sText.replace(result.toString(), path+String.valueOf(result.hashCode()));
//再一次賦值給Textview
tvJobDes.setText(Html.fromHtml(mFvalue, imageGetter, null));
}
};
6、核心代碼4分析:退出Activity或者Fragment的時(shí)候怀酷,回收Bitmap
@Override
protected void onDestroy() {
super.onDestroy();
drawable = null;
//因?yàn)楸緫?yīng)用要下載圖片太多蜕依,所以每次退出的時(shí)候把下載好的本地圖片刪除
FileUtils.delDir(path);
if (bitmap != null && !bitmap.isRecycled()){
bitmap.recycle();
bitmap = null;
drawable = null;
}
if (imageGetter != null){
imageGetter = null;
}
}
8琉雳、FileUtils工具類核心方法:為了刪除下載好的本地圖片
/**
* 刪除方法 這里只會(huì)刪除某個(gè)文件夾下的文件<br/>
* 支持兩級(jí)目錄刪除
*/
public static void delDir(String path) {
File directory = new File(path);
if (directory != null && directory.exists() && directory.isDirectory()) {
for (File item : directory.listFiles()) {
if (item.isDirectory()) {
for (File img : item.listFiles()) {
img.delete();
}
}
item.delete();
}
}
}
8咐吼、FileUtils工具類完整代碼
public class FileUtils {
private static Context mContext;
private static final int DELAY_TIME = 10000;
public final static String CACHE_DIR = "CNMusic";
public final static String GLIDE_CACHE_DIR = "glide";
public final static String SONG_CACHE_DIR = "songs";
public final static String APK_NAME = "cnmusic.apk";
/**
* 應(yīng)用關(guān)聯(lián)的圖片存儲(chǔ)空間
*
* @param context
* @return
*/
public static String getAppPictureDir(Context context) {
File file = context.getExternalFilesDir(Environment.DIRECTORY_PICTURES);
return file.getPath();
}
/**
* 獲取緩存主目錄
*
* @return
*/
public static String getMountedCacheDir() {
if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
// 創(chuàng)建一個(gè)文件夾對(duì)象厢塘,賦值為外部存儲(chǔ)器的目錄
File sdcardDir = Environment.getExternalStorageDirectory();
//得到一個(gè)路徑肌幽,內(nèi)容是sdcard的文件夾路徑和名字
String path = sdcardDir.getPath() + File.separator + CACHE_DIR;
File path1 = new File(path);
if (!path1.exists()) {
path1.mkdirs();
}
return path1.getPath();
}
return null;
}
/**
* 獲取存放歌曲的目錄
*
* @return
*/
public static String getSongDir() {
if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
String path = getMountedCacheDir() + File.separator + SONG_CACHE_DIR;
File path1 = new File(path);
if (!path1.exists()) {
path1.mkdirs();
}
return path1.getPath();
}
return null;
}
/**
* 獲取存放緩存的目錄
*
* @return
*/
public static String getCacheDir() {
File file = mContext.getExternalCacheDir();
return file.getPath();
}
/**
* 刪除方法 這里只會(huì)刪除某個(gè)文件夾下的文件<br/>
* 支持兩級(jí)目錄刪除
*/
public static void cleanCacheDir() {
if (Environment.getExternalStorageState().equals(
Environment.MEDIA_MOUNTED)) {
File directory = mContext.getExternalCacheDir();
if (directory != null && directory.exists() && directory.isDirectory()) {
for (File item : directory.listFiles()) {
if (item.isDirectory()) {
for (File img : item.listFiles()) {
img.delete();
}
}
item.delete();
}
}
}
}
/**
* 刪除方法 這里只會(huì)刪除某個(gè)文件夾下的文件<br/>
* 支持兩級(jí)目錄刪除
*/
public static void delDir(String path) {
File directory = new File(path);
if (directory != null && directory.exists() && directory.isDirectory()) {
for (File item : directory.listFiles()) {
if (item.isDirectory()) {
for (File img : item.listFiles()) {
img.delete();
}
}
item.delete();
}
}
}
/**
* 獲取apk放置的地址
*
* @return
*/
public static String getApkPath() {
String apkPath = getCacheDir() + File.separator + APK_NAME;
File file = new File(apkPath);
if (file.exists()) {
file.delete();
}
return file.getPath();
}
/**
* 讀取Assets目錄下的文件
*
* @param context
* @param name
* @return
*/
public static String getAssets(Context context, String name) {
String result = null;
try {
InputStream in = context.getAssets().open(name); //獲得AssetManger 對(duì)象, 調(diào)用其open 方法取得 對(duì)應(yīng)的inputStream對(duì)象
int size = in.available();//取得數(shù)據(jù)流的數(shù)據(jù)大小
byte[] buffer = new byte[size];
in.read(buffer);
in.close();
result = new String(buffer);
} catch (Exception e) {
}
return result;
}
/**
* 媒體掃描,防止下載后在sdcard中獲取不到歌曲的信息
*
* @param path
*/
public static void mp3Scanner(String path) {
MediaScannerConnection.scanFile(mContext.getApplicationContext(),
new String[]{path}, null, null);
}
public static boolean existFile(String path) {
File path1 = new File(path);
return path1.exists();
}
public static boolean deleteFile(String path) {
File path1 = new File(path);
if (path1.exists()) {
return path1.delete();
}
return false;
}
/**
* open apk
*
* @param context
* @param apk
*/
public static void openApk(Context context, File apk) {
Intent intent = new Intent();
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setAction(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(apk),
"application/vnd.android.package-archive");
context.startActivity(intent);
}
/**
* 獲取下載文件的大小
*
* @param soFarBytes 已下載字節(jié)
* @param totalBytes 總共的字節(jié)
* @return
*/
public static String getProgressSize(long soFarBytes, long totalBytes) {
float progress = soFarBytes * 1.0f / 1024 / 1024;
float total = totalBytes * 1.0f / 1024 / 1024;
String format = "%.1fM/%.1fM";
String str = String.format(Locale.CHINA, format, progress, total);
return str;
}
/**
* 獲取下載進(jìn)度
*
* @param soFarBytes 已下載字節(jié)
* @param totalBytes 總共的字節(jié)
* @return
*/
public static int getProgress(long soFarBytes, long totalBytes) {
if (totalBytes != 0) {
long progress = soFarBytes * 100 / totalBytes;
return (int) progress;
}
return 0;
}
/**
* download apk from server
*
* @param path the apk path
* @param fp file progress listener
* @return apk file
* @throws Exception
*/
public static File getFilefromServerToProgress(String path, FileProgress fp) throws Exception {
//如果相等的話表示當(dāng)前的sdcard掛載在手機(jī)上并且是可用的
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(DELAY_TIME);
int max = conn.getContentLength();
InputStream is = conn.getInputStream();
File file = new File(Environment.getExternalStorageDirectory(), "beats.apk");
FileOutputStream fos = new FileOutputStream(file);
BufferedInputStream bis = new BufferedInputStream(is);
byte[] buffer = new byte[1024];
int len;
int total = 0;
while ((len = bis.read(buffer)) != -1) {
fos.write(buffer, 0, len);
total += len;
//獲取當(dāng)前下載量
if (fp != null)
fp.getProgress(total, max);
}
fos.close();
bis.close();
is.close();
return file;
} else {
return null;
}
}
private static Pattern FilePattern = Pattern.compile("[\\\\/:*?\"<>|]");
public static String filenameFilter(String str) {
return str == null ? null : FilePattern.matcher(str).replaceAll("");
}
public interface FileProgress {
void getProgress(int total, int max);
}
}
9狡孔、主Actiivity或者Fragment完整代碼實(shí)現(xiàn)
**
* 發(fā)布信息詳情查詢
* @author zlc
*
*/
public class JobFbxxxqcxActivity extends BaseActivity {
private static final String TAG = JobFbxxxqcxActivity.class.getSimpleName();
private Context mContext;
private TextView tvJobName;
private TextView tvJobDes;
private TextView tvJobTask;
private TextView tvJobRequest;
private ImageButton mImbBack;
private JobIntentInfoBean mInfoBean;
private String mFinfoid;
private String mFvalue;
private DownLoadHtmlImageUtils downLoadUtils;
//保存文件路徑
private final String path = Environment.getExternalStorageDirectory().getAbsolutePath()+"/htmlimg/";
// String sText = "測試圖片信息:<br><img src=\"http://pic004.cnblogs.com/news/201211/20121108_091749_1.jpg\" />";
@Override
protected void onCreate(Bundle arg0) {
super.onCreate(arg0);
setContentView(R.layout.activity_job_fbxxcx_32);
AppApplication.getInstance().addActivity(this);
initView();
initListener();
initData();
getListData();
}
/**
* 初始化數(shù)據(jù)的方法
*/
private void initData() {
mInfoBean = (JobIntentInfoBean) getIntent().getSerializableExtra
(Constant.INTENT_CONTENT);
if (mInfoBean != null){
mFinfoid = mInfoBean.finfoid;
LogUtils.d(TAG,"mFinfoid===="+mFinfoid);
}
}
/**
* 初始化監(jiān)聽的方法
*/
private void initListener() {
mImbBack.setOnClickListener(this);
}
@Override
protected void initView() {
mContext = this;
loadingDialog = new LoadingDialog(this, R.string.tip_loading_msg);
TextView tvTitle = (TextView) this.findViewById(R.id.tv_base_title_content);
tvTitle.setText(R.string.title_fbxxxq);
mImbBack = (ImageButton) this.findViewById(R.id.imgb_back);
tvJobName = (TextView) findViewById(R.id.tv_job_name);
tvJobDes = (TextView) findViewById(tv_job_des);
tvJobTask = (TextView) findViewById(R.id.tv_job_task);
tvJobRequest = (TextView) findViewById(R.id.tv_job_request);
//設(shè)置鏈接中標(biāo)簽是可以點(diǎn)擊并且可以跳轉(zhuǎn)到瀏覽器打開的
tvJobDes.setClickable(true);
tvJobDes.setMovementMethod(LinkMovementMethod.getInstance());
//整個(gè)TextView居中顯示
// tvJobDes.setGravity(Gravity.CENTER_HORIZONTAL);
}
@Override
public void onClick(View v) {
super.onClick(v);
switch (v.getId()) {
case R.id.imgb_back:
finish();
EventBus.getDefault().post(true);
}
}
/**
* 查詢個(gè)人求職列表信息
*/
private void getListData() {
showLoadingDialog();
StringEntity entity = new JobParam().getCmsInfoParam(mFinfoid);
HttpUtil.post(this, APICommon.API_GETCMSINFO, entity, new AsyncHttpResponseHandler() {
@Override
public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {
LogUtils.d(new String(responseBody));
Gson gson = new Gson();
FbxxxqDataListResponse bean = gson.fromJson(new String
(responseBody), FbxxxqDataListResponse.class);
loadPersionData(bean);
dismissLoadingDialog();
}
@Override
public void onFailure(int statusCode, Header[] headers,
byte[] responseBody, Throwable error) {
dismissLoadingDialog();
}
});
}
/**
* 界面加載數(shù)據(jù)
* @param bean
*/
@SuppressWarnings("unchecked")
private void loadPersionData(FbxxxqDataListResponse bean) {
if (!bean.isSuccess()) {
return;
}
if (bean != null) {
List<InfoidDataResponse> infoidDataResponseList = bean.data;
if (infoidDataResponseList.size() > 0){
InfoidDataResponse infoidDataResponse = infoidDataResponseList.get(0);
mFvalue = infoidDataResponse.getFvalue();
if (!TextUtils.isEmpty(mFvalue)){
setData();
}else {
showWarnStrDialog("發(fā)布信息詳情為空");
}
}
}
}
private void setData() {
//初始化下載類
downLoadUtils=new DownLoadHtmlImageUtils();
//設(shè)置下載類監(jiān)聽事件
downLoadUtils.setOnDownloadListener(onDownloadListener);
//給Textview賦值
tvJobDes.setText(Html.fromHtml(mFvalue,imageGetter,null));
}
Drawable drawable = null;
Bitmap bitmap = null;
Html.ImageGetter imageGetter = new Html.ImageGetter() {
public Drawable getDrawable(String source) {
String fileString=path+String.valueOf(source.hashCode());
Log.i("DEBUG", fileString+"");
Log.i("DEBUG", source+"");
if (!new File(path).exists()){
new File(path).mkdirs();
LogUtils.d(TAG,"創(chuàng)建文件夾成功========");
}
//判斷SD卡里面是否存在圖片文件
if (new File(fileString).exists()) {
Log.i("DEBUG", fileString+" eixts");
//獲取本地文件返回Drawable
bitmap = BitmapFactory.decodeFile(fileString);
drawable = new BitmapDrawable(bitmap);
// drawable=Drawable.createFromPath(fileString);
//設(shè)置圖片邊界
if (drawable != null){
drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
return drawable;
}
return null;
}else {
Log.i("DEBUG", fileString+" Do not eixts");
//啟動(dòng)新線程下載
downLoadUtils.download(source, path+String.valueOf(source.hashCode()));
return drawable;
}
};
};
@Override
protected void onDestroy() {
super.onDestroy();
drawable = null;
FileUtils.delDir(path);
if (bitmap != null && !bitmap.isRecycled()){
bitmap.recycle();
bitmap = null;
drawable = null;
}
if (imageGetter != null){
imageGetter = null;
}
}
Html.TagHandler MyTagHandler = new Html.TagHandler() {
@Override
public void handleTag(boolean opening, String tag, Editable output, XMLReader xmlReader) {
}
};
DownLoadHtmlImageUtils.OnDownloadListener onDownloadListener=new DownLoadHtmlImageUtils.OnDownloadListener() {
//下載進(jìn)度
public void onDownloadUpdate(DownLoadHtmlImageUtils manager, int percent) {
// TODO Auto-generated method stub
Log.i("DEBUG", percent+"");
}
//下載失敗
public void onDownloadError(DownLoadHtmlImageUtils manager, Exception e) {
// TODO Auto-generated method stub
}
//開始下載
public void onDownloadConnect(DownLoadHtmlImageUtils manager) {
// TODO Auto-generated method stub
Log.i("DEBUG", "Start //////");
}
//完成下載
public void onDownloadComplete(DownLoadHtmlImageUtils manager, Object result) {
// TODO Auto-generated method stub
Log.i("DEBUG", result.toString());
//替換sTExt的值离唐,就是把圖片的網(wǎng)絡(luò)路徑換成本地SD卡圖片路徑(最早想法问窃,可以不需要這樣做了)
//sText.replace(result.toString(), path+String.valueOf(result.hashCode()));
//再一次賦值給Textview
tvJobDes.setText(Html.fromHtml(mFvalue, imageGetter, null));
}
};
}
11泡躯、存在的問題
- 當(dāng)接口返回里面包含很多<img>標(biāo)簽丽焊,也就是說要加載很多張圖片咕别,或許這些圖片都是大圖惰拱,那么如何做到更好的緩存呢?我嘗試過先判斷本地有沒有對(duì)應(yīng)的圖片欣孤,沒有的話就去下載昔逗,有的話沿用本地圖片勾怒,不過還是會(huì)報(bào)內(nèi)存溢出。(這里我沒有對(duì)圖片進(jìn)行壓縮段只,因?yàn)槲铱吹较螺d的圖片都是幾十kb或者100多kb)
- <p style="TEXT-ALIGN: center> 圖片居中的標(biāo)簽不起作用鉴扫,居中不了
哪位大神有知道如何實(shí)現(xiàn)的坪创,麻煩告知下
12、參考文章
1古话、https://app.yinxiang.com/shard/s71/nl/14923130/5d9a8167-f62a-45b7-94ae-7ac0318021ba/
2锁施、https://app.yinxiang.com/shard/s71/nl/14923130/0af86dd4-3751-4a6c-b911-c2d170787ba4/
3悉抵、https://app.yinxiang.com/shard/s71/nl/14923130/446ec74b-41ad-4b7e-bedc-e7f2ddb09228/
4摘完、https://app.yinxiang.com/shard/s71/nl/14923130/3acfca20-fc98-4742-ad36-bded31dc754b/
ps:本博文的代碼有一部分是沿用上面大神的代碼孝治,有些是在上面的基礎(chǔ)上進(jìn)行了修改