在项目中(平板)我们自己做了浏览器,本来是有专门团队在开发维护,可是最近由于需求太多等各种原因,直接把源码给到我们自己维护。在维护的过程中遇到一个很有意思的问题,耗费了我不少时间,不过解决后也感到成就感满满。
问题是这样:在下载完图片或是视频音乐应用等文件后,会弹出一个Toast来提示用户打开,可以这个提示框显示的时候不完整,还有后面的一小部分没有显示出来,如图所示:
通过查看代码,调用的部分如下:
private void showStartDownloadToast(final Activity activity, String filename) {
if (activity == null || activity.getCurrentFocus() == null) return;
if (mToast == null) {
mToast = SuperActivityToast.create(activity, new Style(), Style.TYPE_BUTTON);
}
mToast.setButtonText(activity.getString(R.string.open))
.setOnButtonClickListener("download", null, new SuperActivityToast.OnButtonClickListener() {
@Override
public void onClick(View view, Parcelable token) {
try {
Intent intent = new Intent(DownloadManager.ACTION_VIEW_DOWNLOADS);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
activity.startActivity(intent);
} catch (Exception e) {
Logger.e("Downloads app not found");
}
}
})
.setProgressBarColor(Color.WHITE)
.setTouchToDismiss(true)
.setText(filename)
.setDuration(Style.DURATION_VERY_LONG)
.setFrame(Style.FRAME_LOLLIPOP)
.setColor(activity.getResources().getColor(R.color.download_toast_bg))
.setAnimations(Style.ANIMATIONS_POP).show();
}
这个Toast直接使用的是:
import com.github.johnpersano.supertoasts.library.SuperActivityToast;
而在这个SuperActivityToast中使用关于设备是否是平板的判断的:
/**
* Modify various attributes of the SuperActivityToast before being shown.
*/
@Override
protected void onPrepareShow() {
super.onPrepareShow(); // This will take care of many modifications
final FrameLayout.LayoutParams layoutParams = new FrameLayout
.LayoutParams(this.mStyle.width, this.mStyle.height);
// Make some type specific tweaks
switch (this.mStyle.type) {
case Style.TYPE_STANDARD:
break;
case Style.TYPE_BUTTON:
// If NOT Lollipop frame, give padding on each side
if (this.mStyle.frame != Style.FRAME_LOLLIPOP) {
this.mStyle.width = FrameLayout.LayoutParams.MATCH_PARENT;
this.mStyle.xOffset = BackgroundUtils.convertToDIP(24);
this.mStyle.yOffset = BackgroundUtils.convertToDIP(24);
}
//这段即使关于是否是平板的判断,如果是平板的话会设置mstyle.width
// On a big screen device, show the SuperActivityToast on the bottom left
if ((this.mContext.getResources().getConfiguration().screenLayout
& Configuration.SCREENLAYOUT_SIZE_MASK)
>= Configuration.SCREENLAYOUT_SIZE_LARGE) {
this.mStyle.width = BackgroundUtils.convertToDIP(568);//这个值算出来是852,而平板的宽度为800
//导致有一部分没有显示出来
this.mStyle.gravity = Gravity.BOTTOM | Gravity.START;
}
// Set up the Button attributes
final Button button = (Button) this.mView.findViewById(R.id.button);
button.setBackgroundResource(BackgroundUtils
.getButtonBackgroundResource(this.mStyle.frame));
button.setText(this.mStyle.buttonText != null ?
this.mStyle.buttonText.toUpperCase() : "");
button.setTypeface(button.getTypeface(), this.mStyle.buttonTypefaceStyle);
button.setTextColor(this.mStyle.buttonTextColor);
button.setTextSize(this.mStyle.buttonTextSize);
if (this.mStyle.frame != Style.FRAME_LOLLIPOP) {
this.mView.findViewById(R.id.divider).setBackgroundColor(this
.mStyle.buttonDividerColor);
// Set an icon resource if desired
if(this.mStyle.buttonIconResource > 0) {
button.setCompoundDrawablesWithIntrinsicBounds(ResourcesCompat
.getDrawable(mContext.getResources(),
this.mStyle.buttonIconResource,
mContext.getTheme()),
null, null, null);
}
}
if (this.mOnButtonClickListener != null) {
button.setOnClickListener(new View.OnClickListener() {
short clicked = 0;
@Override
public void onClick(View view) {
// Prevent button spamming
if (clicked > 0) return;
clicked++;
mOnButtonClickListener.onClick(view, getButtonToken());
SuperActivityToast.this.dismiss();
}
});
}
break;
case Style.TYPE_PROGRESS_CIRCLE:
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
this.mProgressBar.setIndeterminateTintMode(PorterDuff.Mode.SRC_IN);
this.mProgressBar.setIndeterminateTintList(ColorStateList
.valueOf(this.mStyle.progressBarColor));
}
break;
case Style.TYPE_PROGRESS_BAR:
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
this.mProgressBar.setIndeterminateTintMode(PorterDuff.Mode.SRC_IN);
this.mProgressBar.setIndeterminateTintList(ColorStateList
.valueOf(this.mStyle.progressBarColor));
this.mProgressBar.setProgressTintMode(PorterDuff.Mode.SRC_IN);
this.mProgressBar.setProgressTintList(ColorStateList
.valueOf(this.mStyle.progressBarColor));
}
this.mProgressBar.setProgress(this.mStyle.progress);
this.mProgressBar.setMax(this.mStyle.progressMax);
this.mProgressBar.setIndeterminate(this.mStyle.progressIndeterminate);
break;
}
layoutParams.width = this.mStyle.width;
layoutParams.height = this.mStyle.height;
layoutParams.gravity = this.mStyle.gravity;
layoutParams.bottomMargin = this.mStyle.yOffset;
layoutParams.topMargin = this.mStyle.yOffset;
layoutParams.leftMargin = this.mStyle.xOffset;
layoutParams.rightMargin = this.mStyle.xOffset;
this.mView.setLayoutParams(layoutParams);
// Set up touch to dismiss
if (this.mStyle.touchToDismiss) {
mView.setOnTouchListener(new View.OnTouchListener() {
int timesTouched;
@Override
public boolean onTouch(View v, MotionEvent motionEvent) {
// Prevent repetitive touch events
if (timesTouched == 0 && motionEvent.getAction() == MotionEvent.ACTION_DOWN) dismiss();
timesTouched++;
return false; // Do not consume the event in case a Button listener is set
}
});
} else {
// Make sure no listener is set
mView.setOnTouchListener(null);
}
}
所以找到问题的根源是宽度太大,但是找到问题后解决这个问题却花了一番功夫。
因为SuperActivityToast不能修改,而onPrepareShow()方法是在show()方法中被调用:
/**
* Shows the SuperToast. If any SuperToast is already showing, this SuperToast
* will be enqueued until the others have finished (depending on priority level).
*/
public void show() {
this.onPrepareShow();
Toaster.getInstance().add(this);
AccessibilityUtils.sendAccessibilityEvent(this.mView);
}
所以我在mToast中设置任何width或是Gravity 属性都是没有用的,因为最后调用show()对的时候都会被onPrepareShow()中的宽度覆盖。后来突然就想到为什么不重新定义一个类继承自SuperActivityToast,这样就可以解决设备为平板时自己来设置Toast宽度问题。
于是有了如下解决方式:自定义一个ToastForBigDevice类(原谅我简单粗暴的起名方式),当判断出当前设备为平板的时候,就new ToastForBigDevice(),然后在这个ToastForBigDevice中重写方法onPrepareShow()。
Style mStyle = new Style();
if (mToast == null) {
//mToast = SuperActivityToast.create(activity, new Style(), Style.TYPE_BUTTON);
if ((mContext.getResources().getConfiguration().screenLayout
& Configuration.SCREENLAYOUT_SIZE_MASK)
>= Configuration.SCREENLAYOUT_SIZE_LARGE) {
mToast = new ToastForBigDevice(activity,mStyle, Style.TYPE_BUTTON);
} else {
mToast = SuperActivityToast.create(activity, mStyle, Style.TYPE_BUTTON);
}
}
private class ToastForBigDevice extends SuperActivityToast{
private Style mStyle;
private View mView; //一开始没有加这个mView,结果在设置的时候发现不管怎么设置mStyle的宽度都没用
public ToastForBigDevice(Context context,Style style, int type){
super(context,style,type);
this.mStyle = getStyle();
mView = getView(); //获取当前的View,然后再来设置这个View的宽度,这样就可以完美解决啦
}
@Override
protected void onPrepareShow() {
super.onPrepareShow();
FrameLayout.LayoutParams layoutParams = new FrameLayout
.LayoutParams(this.mStyle.width, this.mStyle.height);
//layoutParams.width = 720;
layoutParams.width = FrameLayout.LayoutParams.MATCH_PARENT; //重新设置layoutParams
layoutParams.gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL;
mView.setLayoutParams(layoutParams); //设置这个View的layoutParams,这样才会起作用,
//其实关键的地方也是在这里
}
}
虽然解决后再回过头来看感觉这么简单,但是真正在解决的过程中其实遇到了不少问题,如一开始没有想到要先获取View再来进行设置导致设置的值不起作用啦等等。能够分析出一个问题产生的根源以及从源头解决这个问题,过程虽然枯燥痛苦,可以解决后的成绩感以及提升感真是让人振奋。mark下这满满的兴奋吧~