设置activity为全透明或者半透明或者弹窗形式
http://blog.csdn.net/zhaozhiwen6140/article/details/52034495
http://blog.csdn.net/ithinklw/article/details/52002662(使用过的方式)(注意要继承activity,清单文件为activity指定theme等)
webview显示图片视频的适配问题
// 适配工具方法
public static String getNewContent(String htmltext,int height){
Document doc= Jsoup.parse(htmltext);
Elements elements1=doc.getElementsByTag("img");
for (Element element : elements1) {
element.attr("width","100%").attr("height","auto");
}
Elements elements2=doc.getElementsByTag("iframe");
for (Element element : elements2) {
element.attr("width","100%").attr("height",height+"");
}
return doc.toString();
}
------------------------------------------------------------------------------
需要:jsoup的jar包
以上方法的第二个参数只为视频设置,因为iframe标签无auto属性,必须按照宽度来动态指定。
在代码中调用时如下:
// 获取屏幕的宽高
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm); // 获取手机屏幕的大小
int w_screen = dm.widthPixels;
int h_screen = dm.heightPixels;
// 宽高比为16:9 ,-10为两边的留白区域
webView.loadData(TimeUtils.getNewContent(data.getContent(), ((DisplayUtil.px2dp(this,w_screen)-10)*9)/16), "text/html; charset=UTF-8", null);
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
解决webview显示图片时,宽度100%填充,按照宽高比设置大图防止出现左右滑动后,发现对于小图宽度同样会被拉伸到100%填充,而图片的宽高数据又是包含在html文本中,
现在需求:大图100%填充显示,小图原样显示,解决方案:
后台在上传图片时,大图不指定尺寸,小图设置尺寸,安卓端处理是更改所有图片的宽度填充,高度auto自适配,但是发现小图却没变大小,究其原因是后台编辑器在上传
图片时如果指定了宽高那么img标签会存在width属性,同时<style>里面也设置了图片的宽度,而两者同时存在时style的优先级高于外层width,安卓端更改的是外层的width,
因内层的style指定的width不变,所以图片还是原大小不会被拉伸,当后台不指定宽高上传时,两者都不会存在,安卓端自动为其添加width属性,所以宽度会填充。
WebView展示图文混排,以及出现文字长度超过屏宽造成的WebView可以左右滑动问题
WebView展示图文混排,以及出现文字长度超过屏宽造成的WebView可以左右滑动问题
简单实现
后台返回数是文字含有图片的图文混排格式,当然图片的就是个url,之前只是文字的话很简单用TextView就能解决,即setText(Html.fromHtml(“请求内容”));图文混排的话我这里用的WebView控件展示的:content为请求返回的内容
WebView webView= (WebView) view.findViewById(R.id.content4);
webView.loadDataWithBaseURL("", content, "text/html", "UTF-8", "");
这样的话就可以完成图文混排的展示了,但后来又发现问题图文混排中图片太宽造成屏幕左右滑动才能看全,这个问题最后让后台调整下图片,前端不做处理,用WebView这种方法咱也没地方处理;但又发现文字过宽不自动换行,可能就是前端展示WebView控件可能不支持js等造成的,再添加如下代码支持js:
WebSettings webSettings= webView.getSettings();
webSettings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN);
webSettings.setJavaScriptEnabled(true);//支持js
---------------------------------------------------------------------------------------------------------
在WebView中展示文章的时候,像让文字左右两端对齐,这样比较好看一些。
只需要在相关标签的CSS样式加上
text-align: justify;
即可,适用于普通web和ios,android等移动平台
比如:
Css代码
.text {
TEXT-INDENT: 2em;
line-height: 150%;
text-align: justify;
}
webview和js互调时必须添加混淆
androidstudio中将.pro混淆文件的有关于webview和js交互时需要添加的混淆注释解开,然后替换为自己的全路径
// class后面为自己项目的类的全路径:包名.类名,该类指的是@javascriptInterface注解的方法所在的类
-keepclassmembers class com.example.admin.tingxueproject.utils.JavascriptInterface {
public *;
}
// 解决在4.2及以上系统可能会丢掉@javascriptInterface注解的混淆
-keepattributes *Annotation*
-keepattributes *JavascriptInterface*
0,将.db数据库文件嵌入app并读取
1.将.db数据库文件保存在项目的assets资产目录下,如data.db
2.创建指向该数据库的db对象,有了db对象就可以对该数据库的表进行增删改查了
// 初始化,只需要调用一次
AssetsDatabaseManager.initManager(getApplication());
// 获取管理对象,因为数据库需要通过管理对象才能够获取
AssetsDatabaseManager mg = AssetsDatabaseManager.getManager();
// 通过管理对象获取数据库
db = mg.getDatabase("data.db");
3.根据db查询数据库的示例,字段模糊匹配,每次取20条记录,pageCount的值为20
cursor = db.query("card", str, "cata like ? and cata2 like ? and rarity = ?", new String[]{"%"+select01+"%","%"+select02+"%",select03}, null, null, null,0+","+pageCount);
list = new ArrayList<>();
while(cursor.moveToNext()){
String cata3 = cursor.getString(cursor.getColumnIndex("cata3"));
String name = cursor.getString(cursor.getColumnIndex("name"));
String pic_s = cursor.getString(cursor.getColumnIndex("pic_s"));
String pic_b = cursor.getString(cursor.getColumnIndex("pic_b"));
Card card = new Card(cata3,name,pic_s,pic_b);
list.add(card);
}
4.请求下一页的20条数据:
// 第一页:0,20
// 第二页:20,20
// 第三页:40,20
current += pageCount;
cursor = db.query("card", str, "cata like ? and cata2 like ? and rarity = ?", new String[]{"%"+select01+"%","%"+select02+"%",select03}, null, null, null,currentStart+","+pageCount);
1.搜索结果关键字高亮显示
1.工具类
package com.example.admin.tingxueproject.utils;
import android.content.Context;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.TextUtils;
import android.text.style.ForegroundColorSpan;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @function 字符串变色工具类
*/
public class StringFormatUtil {
private SpannableStringBuilder spBuilder;
private String wholeStr, highlightStr;
private Context mContext;
private int color;
/**
* @param context 上下文
* @param wholeStr 全部文字
* @param highlightStr 改变颜色的文字
* @param color 颜色
*/
public StringFormatUtil(Context context, String wholeStr, String highlightStr, int color) {
this.mContext = context;
this.wholeStr = wholeStr;
this.highlightStr = highlightStr;
this.color = color;
}
/**
* 填充颜色
*
* @return StringFormatUtil
*/
public StringFormatUtil fillColor() {
if (!TextUtils.isEmpty(wholeStr) && !TextUtils.isEmpty(highlightStr)) {
spBuilder = new SpannableStringBuilder(wholeStr);
//匹配规则
Pattern p = Pattern.compile(highlightStr);
//匹配字段
Matcher m = p.matcher(spBuilder);
//上色
color = mContext.getResources().getColor(color);
//开始循环查找里面是否包含关键字
while (m.find()) {
int start = m.start();
int end = m.end();
spBuilder.setSpan(new ForegroundColorSpan(color), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
return this;
}
return null;
}
/**
* 获取到已经更改好的结果(这个时候已经实现了高亮,在获取这个result的时候不要toString()要不然会把色调去除的)
*
* @return result
*/
public SpannableStringBuilder getResult() {
if (spBuilder != null) {
return spBuilder;
}
return null;
}
}
2.在Adapter中使用如下:
// 搜索结果关键字高亮显示
// context 总的文本 关键字 关键字的颜色
StringFormatUtil mFormatUtil = new StringFormatUtil(ZXSousuoActivity.this, search.getTitle(), string,
R.color.colorAccent).fillColor();
holder.tvTitle.setText(mFormatUtil.getResult());
2.APK二次打包以及优化
二次打包
应用场景:apk经过加固(具体怎么操作不清楚,比较高端),把我们的签名给破坏了,需要用命令进行二次打包
手动签名:(JDK8版本下进行手动签名的完整命令)
jarsigner -keystore yiyou.jks(签名文件) -storepass tingxue666(密钥) -signedjar 22.apk(已签名apk) 11.apk(未签名apk) yiyou(别名)
-digestalg SHA1 -sigalg MD5withRSA -tsa http://timestamp.digicert.com
使用JDK8版本进行手动签名时必须要加上如下两个参数:-digestalg SHA1 和 -sigalg MD5withRSA,否则签名完apk安装时会提示错误:Failure [INSTALL_PARSE_FAILED_NO_CERTIFICATES]
如果不设置tsa参数,会有如下警告:
警告:
未提供 -tsa 或 -tsacert, 此 jar 没有时间戳。如果没有时间戳, 则在签名者证书的到期日期 (2070-05-29) 或以后的任何撤销日期之后, 用户可能无法验证此 jar。
经测试:将Java环境变量切换到jdk6后,不设置digestalg、sigalg、tsa3个参数, 一切都OK
手动打包时需要注意JDK版本,JDK有版本区分,如果使用的keystore是用JDK6生成的,用JDK8重新签名的话打不开应用直接闪退,所以需要准备对应版本的JDK。
进入命令行(cmd),并cd到jdk的bin目录下(没切到bin目录下会默认去JAVAHOME下找),然后输入上面的完整签名命令即可,如下图:
注意图中仅参考使用方式,具体的命令书写格式以上面的jdk8完整签名命令为正确,另外建议将未签名apk和签名文件拷贝放到和jarsigner工具同级的目录下,这样绝对路径写法就可以省去了。
zipalign优化
zipalign优化的最根本目的是帮助操作系统更高效率的根据请求索引资源,将resource-handling code统一将Data structure alignment(数据结构对齐标准:DSA)限定为4-byte boundaries。
优化处理方法一:使用命令行
1、在Android SDK的tools文件夹下,找到zipalign.exe文件。
2、把你要优化的apk复制到你解压出来的tools文件夹下。
开始->运行->CMD调出命令行窗口
命令行下输入:
zipalign -v 4 22.apk(需优化) 33.apk(优化后)
其中这里-v代表详细输出,4代表对齐为4个字节。
如下图:
优化处理方法二:在build.gradle配置
release {
//Zipalign优化
zipAlignEnabled true
}
签名:
jarsigner -keystore yiyou.jks(签名文件) -storepass tingxue666(密钥) -signedjar 22.apk(已签名apk) 11.apk(未签名apk) yiyou(别名) -digestalg SHA1 -sigalg MD5withRSA -tsa http://timestamp.digicert.com
优化:
zipalign -v 4 22.apk(需优化) 33.apk(优化后)
3.TextView两端对齐
package com.example.admin.tingxueproject.weight;
import android.content.Context;
import android.graphics.Canvas;
import android.text.Layout;
import android.text.StaticLayout;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.widget.TextView;
public class JustifyTextView extends TextView {
/** TextView的总宽度*/
private int mViewWidth;
/** 行高*/
private int mLineY;
public JustifyTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public JustifyTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public JustifyTextView(Context context) {
super(context);
}
@Override
protected void onDraw(Canvas canvas) {
TextPaint paint = getPaint();
paint.setColor(getCurrentTextColor());
paint.drawableState = getDrawableState();
mViewWidth = getMeasuredWidth();//拿到textview的实际宽度
String text = getText().toString();
mLineY = 0;
mLineY += getTextSize();
Layout layout = getLayout();
for (int i = 0; i < layout.getLineCount(); i++) {//每行循环
int lineStart = layout.getLineStart(i);
int lineEnd = layout.getLineEnd(i);
String line = text.substring(lineStart, lineEnd);//获取到TextView每行中的内容
float width = StaticLayout.getDesiredWidth(text, lineStart,lineEnd, getPaint());
if (needScale(line)) {
if (i == layout.getLineCount() - 1) {//最后一行不需要重绘
canvas.drawText(line, 0, mLineY, paint);
} else {
drawScaleText(canvas, lineStart, line, width);
}
} else {
canvas.drawText(line, 0, mLineY, paint);
}
mLineY += getLineHeight();//写完一行以后,高度增加一行的高度
System.out.println("lineHeight---" + getLineHeight());
}
}
/**
* 重绘此行
*
* @param canvas 画布
* @param lineStart 行头
* @param line 该行所有的文字
* @param lineWidth 该行每个文字的宽度的总和
*/
private void drawScaleText(Canvas canvas, int lineStart, String line,
float lineWidth) {
float x = 0;
if (isFirstLineOfParagraph(lineStart, line)) {
String blanks = " ";
canvas.drawText(blanks, x, mLineY, getPaint());// 以 (x, mLineY) 为起点,画出blanks
float bw = StaticLayout.getDesiredWidth(blanks, getPaint());// 画出一个空格需要的宽度
x += bw;
line = line.substring(3);
}
// 比如说一共有5个字,中间隔了4个空儿,
// 那就用整个TextView的宽度 - 这5个字的宽度,
//然后除以4,填补到这4个空儿中
float d = (mViewWidth - lineWidth) / (line.length() - 1);
for (int i = 0; i < line.length(); i++) {
String c = String.valueOf(line.charAt(i));
float cw = StaticLayout.getDesiredWidth(c, getPaint());
canvas.drawText(c, x, mLineY, getPaint());
x += cw + d;
}
}
/**
* 判断是不是段落的第一行。
* 一个汉字相当于一个字符,此处判断是否为第一行的依据是:
* 字符长度大于3且前两个字符为空格
* @param lineStart
* @param line
* @return
*/
private boolean isFirstLineOfParagraph(int lineStart, String line) {
return line.length() > 3 && line.charAt(0) == ' '
&& line.charAt(1) == ' ';
}
/**
* 判断需不需要缩放
* 该行最后一个字符不是换行符的时候返回true,
* 该行最后一个字符是换行符的时候返回false
* @param line
* @return
*/
private boolean needScale(String line) {
if (line.length() == 0) {
return false;
} else {
return line.charAt(line.length() - 1) != '\n';//该行最后一个字符不是换行符的时候返回true,是换行符的时候返回false
}
}
}
4.仿支付余额滚动效果
1.自定义的TextView类:
package com.example.admin.mytest666666;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.widget.TextView;
import java.text.DecimalFormat;
/**
* 数字滚动的textView
*/
public class NumberRunningTextView extends TextView {
private static final int MONEY_TYPE = 0;
private static final int NUM_TYPE = 1;
private int textType;//内容的类型,默认是金钱类型
private boolean useCommaFormat;//是否使用每三位数字一个逗号的格式,让数字显得比较好看,默认使用
private boolean runWhenChange;//是否当内容有改变才使用动画,默认是
private int duration;//动画的周期,默认为800ms
private int minNum;//显示数字最少要达到这个数字才滚动 默认为1
private float minMoney;//显示金额最少要达到这个数字才滚动 默认为0.3
private DecimalFormat formatter = new DecimalFormat("0.00");// 格式化金额,保留两位小数
private String preStr;
public NumberRunningTextView(Context context) {
this(context, null);
}
public NumberRunningTextView(Context context, AttributeSet attrs) {
this(context, attrs, android.R.attr.textViewStyle);
}
public NumberRunningTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.NumberRunningTextView);
duration = ta.getInt(R.styleable.NumberRunningTextView_duration, 1000);
textType = ta.getInt(R.styleable.NumberRunningTextView_textType, MONEY_TYPE);
useCommaFormat = ta.getBoolean(R.styleable.NumberRunningTextView_useCommaFormat, true);
runWhenChange = ta.getBoolean(R.styleable.NumberRunningTextView_runWhenChange,true);
minNum = ta.getInt(R.styleable.NumberRunningTextView_minNum, 3);
minMoney = ta.getFloat(R.styleable.NumberRunningTextView_minMoney,0.1f);
ta.recycle();
}
/**
* 设置需要滚动的金钱(必须为正数)或整数(必须为正数)的字符串
*
* @param str
*/
public void setContent(String str) {
//如果是当内容改变的时候才执行滚动动画,判断内容是否有变化
if (runWhenChange){
if (TextUtils.isEmpty(preStr)){
//如果上一次的str为空
preStr = str;
useAnimByType(str);
return;
}
//如果上一次的str不为空,判断两次内容是否一致
if (preStr.equals(str)){
//如果两次内容一致,则不做处理
return;
}
preStr = str;//如果两次内容不一致,记录最新的str
}
useAnimByType(str);
}
private void useAnimByType(String str) {
if (textType == MONEY_TYPE) {
playMoneyAnim(str);
} else if (textType == NUM_TYPE){
playNumAnim(str);
}
}
/**
* 播放金钱数字动画的方法
*
* @param moneyStr
*/
public void playMoneyAnim(String moneyStr) {
String money = moneyStr.replace(",", "").replace("-", "");//如果传入的数字已经是使用逗号格式化过的,或者含有符号,去除逗号和负号
try {
float finalFloat = Float.parseFloat(money);
if (finalFloat < minMoney) {
//如果传入的为0,则直接使用setText()
setText(moneyStr);
return;
}
ValueAnimator floatAnimator = ValueAnimator.ofFloat(0, finalFloat);
floatAnimator.setDuration(duration);
floatAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float currentNum = (float) animation.getAnimatedValue();
String str = formatter.format(Double.parseDouble(String.valueOf(currentNum)));//格式化成两位小数
// 更新显示的内容
if (useCommaFormat) {
//使用每三位数字一个逗号的格式
String formatStr = StringUtils.addComma(str);//三位一个逗号格式的字符串
setText(formatStr);
} else {
setText(str);
}
}
});
floatAnimator.start();
} catch (NumberFormatException e) {
e.printStackTrace();
this.setText(moneyStr);//如果转换Double失败则直接用setText
}
}
/**
* 播放数字动画的方法
*
* @param numStr
*/
public void playNumAnim(String numStr) {
String num = numStr.replace(",", "").replace("-", "");//如果传入的数字已经是使用逗号格式化过的,或者含有符号,去除逗号和负号
try {
int finalNum = Integer.parseInt(num);
if (finalNum < minNum) {
//由于是整数,每次是递增1,所以如果传入的数字比帧数小,则直接使用setText()
this.setText(numStr);
return;
}
ValueAnimator intAnimator = new ValueAnimator().ofInt(0, finalNum);
intAnimator.setDuration(duration);
intAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int currentNum = (int) animation.getAnimatedValue();
setText(String.valueOf(currentNum));
}
});
intAnimator.start();
} catch (NumberFormatException e) {
e.printStackTrace();
setText(numStr);//如果转换Double失败则直接用setText
}
}
}
2.自定义属性attr.xml文件:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="NumberRunningTextView">
<attr name="duration" format="integer"></attr>
<attr name="minNum" format="integer"></attr>
<attr name="minMoney" format="float"></attr>
<!--内容的格式-->
<attr name="textType">
<enum name="money" value="0"></enum>
<enum name="num" value="1"></enum>
</attr>
<!--是否使用每三位数字一个逗号-->
<attr name="useCommaFormat" format="boolean"></attr>
<!--是否当内容改变的时候使用动画,不改变则不使用动画-->
<attr name="runWhenChange" format="boolean"></attr>
</declare-styleable>
</resources>
3.工具类StringUtils.java代码:
package com.example.admin.mytest666666;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class StringUtils {
/**
* 格式化字符串,每三位用逗号隔开
*
* @param str
* @return
*/
public static String addComma(String str) {
str = new StringBuilder(str).reverse().toString(); //先将字符串颠倒顺序
if (str.equals("0")) {
return str;
}
String str2 = "";
for (int i = 0; i < str.length(); i++) {
if (i * 3 + 3 > str.length()) {
str2 += str.substring(i * 3, str.length());
break;
}
str2 += str.substring(i * 3, i * 3 + 3) + ",";
}
if (str2.endsWith(",")) {
str2 = str2.substring(0, str2.length() - 1);
}
//最后再将顺序反转过来
String temp = new StringBuilder(str2).reverse().toString();
//将最后的,去掉
return temp.substring(0, temp.lastIndexOf(",")) + temp.substring(temp.lastIndexOf(",") + 1, temp.length());
}
public static String formatDoublePointTwo(double money) {
//保持小数点后两位
DecimalFormat formater = new DecimalFormat();
formater.setMaximumFractionDigits(2);
formater.setGroupingSize(0);
formater.setRoundingMode(RoundingMode.FLOOR);
return formater.format(money);
}
public static String formatTimeYMD(String time) {
try {
Date date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(time);
return new SimpleDateFormat("yyyy-MM-dd").format(date);
} catch (ParseException e) {
e.printStackTrace();
return "日期获取失败";
}
}
}
4.1.在布局文件layout中定义如下:
<com.chaychan.viewlib.NumberRunningTextView
android:id="@+id/tv_num"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="200"
android:textColor="#fff"
android:textSize="30sp"
android:textStyle="bold"
app:textType="num"
/>
1.textType是用于指定内容的格式,总共有money(金钱格式,带小数)和num(整数格式),默认是金钱的格式,不配置textType的话,默认就是使用金钱格式。
2.默认金额显示的整数部分每三位添加一个逗号,如果不想要这种格式的数字,可以在布局文件中,NumberRunningTextView的配置中,将useCommaFormat设置为false,这样最终的数字就不会是带有逗号了。
4.2.在activity中进行赋值:
tv_num = (NumberRunningTextView) findViewById(R.id.tv_num);
tv_money = (NumberRunningTextView) findViewById(R.id.tv_money);
tv_num.setContent("200");
tv_money.setContent("1354.00");
1.当一开始进入界面的时候,初始化数据完毕,NumberRunningTextView设置数据完毕,会自动执行数字滚动的动画,如果进行刷新操作,从服务器获取新的数据,重新设置数据,NumberRunningTextView会自动判断传入的内容是否有变化,如果没有变化,则不会再次滚动,而当金额发生变化后,就会再次滚动,如果想要在刷新的时候,无论内容是否有变化都要执行滚动动画的话,可以在布局文件中,NumberRunningTextView的配置中,将runWhenChange设置为false即可,此时,无论内容是否有变化,都会执行滚动动画。
2.NumberRunningTextView默认是30帧,如果需要修改帧数,可以在布局文件中,NumberRunningTextView的配置中,将frameNum设置为自己想要的帧数。
5.自定义跟随TextView一起居中的drawable
package com.example.admin.tingxueproject.weight;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.widget.TextView;
/**
* drawableLeft与文本一起居中显示
*/
public class DrawableCenterTextView extends TextView {
public DrawableCenterTextView(Context context) {
super(context);
}
public DrawableCenterTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public DrawableCenterTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onDraw(Canvas canvas) {
Drawable[] drawables = getCompoundDrawables();
if (drawables != null) {
Drawable drawableLeft = drawables[0];
if (drawableLeft != null) {
float textWidth = getPaint().measureText(getText().toString());
int drawablePadding = getCompoundDrawablePadding();
int drawableWidth = 0;
drawableWidth = drawableLeft.getIntrinsicWidth();
float bodyWidth = textWidth + drawableWidth + drawablePadding;
canvas.translate((getWidth() - bodyWidth) / 2, 0);
}
}
super.onDraw(canvas);
}
}
用法和一般的TextView用法相同
自定义控件使用DrawableLeft/Right图片和文字同时居中:https://blog.csdn.net/eileenching/article/details/48393531
6.Glide加载图片的两种方式,动态解决图片适配问题
两种方式如下:
// 获取到原图对应的
// Glide.with(mActivity).load(GlobalUrl.BASE_URL + image1 ).into(holder.iv1); // 方式1
// 方式2
Glide.with(mActivity).load(GlobalUrl.BASE_URL + image1).asBitmap()
.placeholder(R.mipmap.default2)
.into(new SimpleTarget<Bitmap>(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL) {
@Override
public void onResourceReady(Bitmap resource, GlideAnimation<? super Bitmap> glideAnimation) {
int imageWidth = resource.getWidth(); // 获取到图片的宽度
int imageHeight = resource.getHeight(); // 获取到图片的高度
Log.d("test","原始图片的宽度为:"+imageWidth);
Log.d("test","原始图片的高度为:"+imageHeight);
// 判断宽和高的大小关系,以长的一边为基准
if(imageWidth == imageHeight){
Log.d("test","宽度等于高度");
// 如果宽高相等
RelativeLayout.LayoutParams para = (RelativeLayout.LayoutParams) holder.rl.getLayoutParams();
// 动态设置imageview的宽高,然后再加载图片
// 获取到屏幕的宽度
DisplayMetrics dm = new DisplayMetrics();
mActivity.getWindowManager().getDefaultDisplay().getMetrics(dm); // 获取手机屏幕的大小
para.height = para.width = (int)(dm.widthPixels/3*1.7);
}else if(imageWidth > imageHeight){
// 如果宽高相等
RelativeLayout.LayoutParams para = (RelativeLayout.LayoutParams) holder.rl.getLayoutParams();
// 动态设置imageview的宽高,然后再加载图片
// 获取到屏幕的宽度
DisplayMetrics dm = new DisplayMetrics();
mActivity.getWindowManager().getDefaultDisplay().getMetrics(dm); // 获取手机屏幕的大小
para.width = (int)(dm.widthPixels/3*1.7);
para.height = para.width*imageHeight/imageWidth;
}else if(imageWidth < imageHeight){
// 如果宽高相等
RelativeLayout.LayoutParams para = (RelativeLayout.LayoutParams) holder.rl.getLayoutParams();
// 动态设置imageview的宽高,然后再加载图片
// 获取到屏幕的宽度
DisplayMetrics dm = new DisplayMetrics();
mActivity.getWindowManager().getDefaultDisplay().getMetrics(dm); // 获取手机屏幕的大小
para.height = (int)(dm.widthPixels/3*1.7);
para.width = para.height*imageWidth/imageHeight;
}
// 设置图片
holder.iv1.setImageBitmap(resource);
}
});
7.Glide加载长图适配
http://blog.csdn.net/libra_louis/article/details/58604149
如:其中imageview(iv1)的宽高均为填充父容器,而他的父容器即为相对布局rl,rl的宽高指定为105dp。(防止滑动时尺寸的变化)
Glide.with(mActivity).load(GlobalUrl.BASE_URL + image1).asBitmap()
.into(new SimpleTarget<Bitmap>(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL) {
@Override
public void onResourceReady(Bitmap resource, GlideAnimation<? super Bitmap> glideAnimation) {
// 获取到屏幕的宽度
DisplayMetrics dm = new DisplayMetrics();
mActivity.getWindowManager().getDefaultDisplay().getMetrics(dm); // 获取手机屏幕的大小
int imageWidth = resource.getWidth(); // 获取到图片的宽度
int imageHeight = resource.getHeight(); // 获取到图片的高度
// Log.d("test","原始图片的宽度为:"+imageWidth);
// Log.d("test","原始图片的高度为:"+imageHeight);
// 判断宽和高的大小关系,以长的一边为基准
if(imageWidth == imageHeight){
// 如果宽高相等
RelativeLayout.LayoutParams para = (RelativeLayout.LayoutParams) holder.rl.getLayoutParams();
// 动态设置imageview的宽高,然后再加载图片
para.height = para.width = (int)(dm.widthPixels/3*1.7);
holder.rl.setLayoutParams(para);
holder.iv1.setImageBitmap(resource);
}else if(imageWidth > imageHeight){
// 如果宽高相等
RelativeLayout.LayoutParams para = (RelativeLayout.LayoutParams) holder.rl.getLayoutParams();
// 动态设置imageview的宽高,然后再加载图片
para.width = (int)(dm.widthPixels/3*1.7);
para.height = para.width*imageHeight/imageWidth;
holder.rl.setLayoutParams(para);
holder.iv1.setImageBitmap(resource);
}else if(imageWidth < imageHeight){
// 如果宽小于高,判断是否为长图
// if(imageHeight > 4096) {
if(imageHeight > dm.heightPixels ) {
RelativeLayout.LayoutParams para = (RelativeLayout.LayoutParams) holder.rl.getLayoutParams();
para.width = DisplayUtil.dp2px(mActivity,105);
para.height = DisplayUtil.dp2px(mActivity,105);
holder.rl.setLayoutParams(para);
holder.iv1.setLayoutParams(para);
// 开始加载图片
Glide.with(mActivity)
.load(GlobalUrl.BASE_URL + image)
.dontAnimate()
.into(holder.iv1);
}else{
RelativeLayout.LayoutParams para = (RelativeLayout.LayoutParams) holder.rl.getLayoutParams();
para.height = (int)(dm.widthPixels/3*1.7);
para.width = para.height*imageWidth/imageHeight;
holder.rl.setLayoutParams(para);
holder.iv1.setImageBitmap(resource);
}
}
}
});
8.webview和js互调时必须添加混淆
androidstudio中将.pro混淆文件的有关于webview和js交互时需要添加的混淆注释解开,然后替换为自己的全路径
// class后面为自己项目的类的全路径:包名.类名,该类指的是@javascriptInterface注解的方法所在的类
-keepclassmembers class com.example.admin.tingxueproject.utils.JavascriptInterface {
public *;
}
// 解决在4.2及以上系统可能会丢掉@javascriptInterface注解的混淆
-keepattributes *Annotation*
-keepattributes *JavascriptInterface*
9.webview显示图片视频的适配问题
// 适配工具方法
public static String getNewContent(String htmltext,int height){
Document doc= Jsoup.parse(htmltext);
Elements elements1=doc.getElementsByTag("img");
for (Element element : elements1) {
element.attr("width","100%").attr("height","auto");
}
Elements elements2=doc.getElementsByTag("iframe");
for (Element element : elements2) {
element.attr("width","100%").attr("height",height+"");
}
return doc.toString();
}
------------------------------------------------------------------------------
需要:jsoup的jar包
以上方法的第二个参数只为视频设置,因为iframe标签无auto属性,必须按照宽度来动态指定。
在代码中调用时如下:
// 获取屏幕的宽高
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm); // 获取手机屏幕的大小
int w_screen = dm.widthPixels;
int h_screen = dm.heightPixels;
// 宽高比为16:9 ,-10为两边的留白区域
webView.loadData(TimeUtils.getNewContent(data.getContent(), ((DisplayUtil.px2dp(this,w_screen)-10)*9)/16), "text/html; charset=UTF-8", null);
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
解决webview显示图片时,宽度100%填充,按照宽高比设置大图防止出现左右滑动后,发现对于小图宽度同样会被拉伸到100%填充,而图片的宽高数据又是包含在html文本中,
现在需求:大图100%填充显示,小图原样显示,解决方案:
后台在上传图片时,大图不指定尺寸,小图设置尺寸,安卓端处理是更改所有图片的宽度填充,高度auto自适配,但是发现小图却没变大小,究其原因是后台编辑器在上传
图片时如果指定了宽高那么img标签会存在width属性,同时<style>里面也设置了图片的宽度,而两者同时存在时style的优先级高于外层width,安卓端更改的是外层的width,
因内层的style指定的width不变,所以图片还是原大小不会被拉伸,当后台不指定宽高上传时,两者都不会存在,安卓端自动为其添加width属性,所以宽度会填充。
9.WebView展示图文混排,以及出现文字长度超过屏宽造成的WebView可以左右滑动问题
WebView展示图文混排,以及出现文字长度超过屏宽造成的WebView可以左右滑动问题
简单实现
后台返回数是文字含有图片的图文混排格式,当然图片的就是个url,之前只是文字的话很简单用TextView就能解决,即setText(Html.fromHtml(“请求内容”));图文混排的话我这里用的WebView控件展示的:content为请求返回的内容
WebView webView= (WebView) view.findViewById(R.id.content4);
webView.loadDataWithBaseURL("", content, "text/html", "UTF-8", "");
这样的话就可以完成图文混排的展示了,但后来又发现问题图文混排中图片太宽造成屏幕左右滑动才能看全,这个问题最后让后台调整下图片,前端不做处理,用WebView这种方法咱也没地方处理;但又发现文字过宽不自动换行,可能就是前端展示WebView控件可能不支持js等造成的,再添加如下代码支持js:
WebSettings webSettings= webView.getSettings();
webSettings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN);
webSettings.setJavaScriptEnabled(true);//支持js
---------------------------------------------------------------------------------------------------------
在WebView中展示文章的时候,像让文字左右两端对齐,这样比较好看一些。
只需要在相关标签的CSS样式加上
text-align: justify;
即可,适用于普通web和ios,android等移动平台
比如:
Css代码
.text {
TEXT-INDENT: 2em;
line-height: 150%;
text-align: justify;
}
10.将glide下载的缓存图片保存在本地
在这里插入代码片项目需求:使用glide加载显示网络图片,然后在图片上长按出现保存到本地选项,点击可以保存到本地。
解决方案:因为是网络图片,所以保存到本地是否会有下载的过程??
Glide加载显示图片已经将图片下载并且缓存到了本地,我们只需将该缓存重新保存在手机系统相册即可,那么如何将glide的缓存保存到本地呢?
实现的方法如下:(需要写入SD卡的权限)
// 思路:从glide中获取到指定url的bitmap对象,然后将其转换成二进制再写入本地,获取bitmap必须放在子线程中来完成,
@NeedsPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)
void saveImage(final String s1) {
//将ImageView中的图片转换成Bitmap
/*iv.buildDrawingCache();
Bitmap bitmap = iv.getDrawingCache();*/
new Thread(new Runnable() {
@Override
public void run() {
Bitmap bitmap = null;
try {
bitmap = Glide.with(ImageActivity.this)
.load(image)
.asBitmap()
.into(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL)
.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
if(bitmap != null){
//将Bitmap 转换成二进制,写入本地
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
byte[] byteArray = stream.toByteArray();
File dir = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/yiyou");
Log.d("test","dir的路径地址为:"+dir.getPath());
if (!dir.isFile()) {
dir.mkdir();
}
/*// 获取当前时间戳字符串,精确到毫秒
SimpleDateFormat fmt = new SimpleDateFormat("yyyyMMddHHmm"); //精确到毫秒
String suffix = fmt.format(new Date());*/
String s = s1;
File file = new File(dir, s);
Message msg = new Message();
msg.what = 0x22;
msg.obj = file.getPath();
mHandler.sendMessage(msg);
try {
FileOutputStream fos = new FileOutputStream(file);
fos.write(byteArray, 0, byteArray.length);
fos.flush();
//用广播通知相册进行更新相册
Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
Uri uri = Uri.fromFile(file);
intent.setData(uri);
sendBroadcast(intent);
// Toast.makeText(ImageActivity.this, "图片保存成功,保存路径为"+, Toast.LENGTH_SHORT).show();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}).start();
}