100字范文,内容丰富有趣,生活中的好帮手!
100字范文 > Android图片海报制作-自定义文字排版控件组件

Android图片海报制作-自定义文字排版控件组件

时间:2019-03-12 21:23:22

相关推荐

Android图片海报制作-自定义文字排版控件组件

项目地址:/coolstar1204/MakePoster

今天主要讲一下项目主要控件,文字排版控件组,实现类似QQ音乐歌词海报效果。

控件主要功能点

可设置背景图片可设置标题文字,并支持标题文字自动居中、超长自动…可设置图片颜色效果,实现黑白、旧照片、变暗、变亮等效果(有些效果还不太理想)可增加多行自定义文字、支持文字设置阴影、颜色、大小、居中居右居左等对齐通用设置,支持文字特效

排版(横向、竖向、不同行等宽不同字体大小效果等)

控件设计结构

核心类

IPoster:字义了排版功能,直接子类有DiffSizePoster、HorizontalPoster、VerticalPoster三个类。

IBmpDrawer:定义了背景图绘制功能,实现类目前只有BmpDrawer,支持ColorMatrix设置

TextDrawer:控件基类,继承于View控件,内部管理上二个接口实现类、增加了标题栏和Logo的绘制功能、导出海报图片功能。

TextDrawer

核心函数有:

@Overrideprotected void onDraw(Canvas canvas) {onDrawBackBmp(canvas);//画文字,文字位置使用scroll变量偏移,达到拖动效果canvas.save();canvas.translate(mScrollX,mScrollY);if(poster!=null){poster.onPostDraw(canvas);}canvas.restore();//画标题文字与酷我logodrawLogoAndTitle(canvas); //画标题和logo}

private float drawTitle(float logoTop, Canvas canvas) {if(!TextUtils.isEmpty(kuwoMusicInfo)){float titleTargetWidth = bmpDrawer.getBmpScaleRect().width()-mTitleMarginValue-mTitleMarginValue; //有时有缩放显示的情况,文字也要同步变窄,默认是和控件一样宽float txtHeight = titlePaint.getFontMetrics().bottom-titlePaint.getFontMetrics().top;float txtTop = logoTop-txtHeight-V_SAPCE*2; //文字高度是在图标上方,文字高度上下各留20间距的区域中,居中显示RectF txtRect = new RectF(mTitleMarginValue,txtTop,getWidth()-mTitleMarginValue,logoTop);Paint.FontMetricsInt fontMetrics = titlePaint.getFontMetricsInt();//判断字符串长度是不是超长,超长转为...String drawTxt = kuwoMusicInfo;float txtWidth = titlePaint.measureText(kuwoMusicInfo);if(txtWidth>titleTargetWidth){float tailWidth = titlePaint.measureText("...");float[] wordWidths = new float[kuwoMusicInfo.length()];titlePaint.getTextWidths(kuwoMusicInfo,wordWidths);float tmpWidth = tailWidth;int wordIdx = kuwoMusicInfo.length()-1; //默认是显示全部字符for(int i=0;i<wordWidths.length;i++){if((tmpWidth+wordWidths[i])>titleTargetWidth){wordIdx = i;break;}else{tmpWidth += wordWidths[i];}}drawTxt = kuwoMusicInfo.substring(0,wordIdx)+"..."; //截取一部分标题内容}float baseline = (txtRect.bottom + txtRect.top - fontMetrics.bottom - fontMetrics.top) / 2;// 下面这行是实现水平居中,drawText对应改为传入targetRect.centerX()titlePaint.setTextAlign(Paint.Align.CENTER);canvas.drawText(drawTxt, txtRect.centerX(), baseline, titlePaint);// canvas.drawRect(txtRect,titlePaint);return getHeight() - txtRect.top; //高度减去文字的上边坐标,得到文字与logo的总高度}return 0f;}

private Bitmap innerBuildPost(String filePath, int outWidth, int outHeight, boolean saveFile){if(saveFile&& FileUtils.isExist(filePath)){if(false == FileUtils.deleteFile(filePath)){return null;}}try {Bitmap outBmp = Bitmap.createBitmap(outWidth,outHeight, Bitmap.Config.ARGB_8888);LogMgr.d("PostBmp","width:"+outWidth+",Height:"+outWidth);Canvas canvas = new Canvas(outBmp);ImageView.ScaleType oldScaleType = bmpDrawer.getBmpScaleType();bmpDrawer.outputDraw(canvas,outWidth,outHeight);float scaleX = outWidth*1.0f/getWidth(); //获取屏幕与真实图片的比例float scaleY = outHeight*1.0f/getHeight(); //获取屏幕与真实图片的比例LogMgr.d("PostBmp","scaleX:"+scaleX+",scaleY:"+scaleY);Matrix matrix = canvas.getMatrix();canvas.save();if(Math.abs(scaleX-1.0f)>0.01|| Math.abs(scaleY-1.0f)>0.01){matrix.setScale(scaleX,scaleY,0,0); //缩放处理显示与原图的位置关系canvas.setMatrix(matrix);}if(poster!=null){canvas.save();canvas.translate(mScrollX,mScrollY);poster.onPostDraw(canvas);canvas.restore();}drawLogoAndTitle(canvas);canvas.restore();if(saveFile){ //如果设置要保存文件,则保存到本地sd卡中,如果不要,则直接返回bitmap对象File bmpFile = new File(filePath);FileOutputStream fout = new FileOutputStream(bmpFile);press(pressFormat.JPEG,100,fout);fout.flush();fout.close();}return outBmp;} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} catch (Throwable e){System.gc();e.printStackTrace();}return null;}

HorizontalPoster

本类实现文字的横向排版、运行多行的三种对齐方式,同时其子类实现了跳动文字效果、下划线效果、带符号线条装饰效果等。其核心函数是各类中的

public void updateTextRect(int parentWidth, int parentHeight) {Log.d("Poster","------------updateTextRect-----------");if(textList!=null&&textList.length>0){if(drawTextList==null){drawTextList = new ArrayList<TxtRowInfo>(textList.length*2); //默认设置是歌词行数2倍,不能每个都换行吧!}drawTextList.clear();Paint.FontMetrics pfm = textPaint.getFontMetrics();txtHeight = pfm.descent-pfm.ascent; //保存现有字号下单个字的高度maxWidth = 0;//保存最大宽度float totalHeight=-pfm.top; //保存总高度totalHeight+=margin_Top; //加上上面的空隙float rawWidth;//保存每一行的宽度for(int i=0;i<textList.length;i++){rawWidth = textPaint.measureText(textList[i]);if(rawWidth>(parentWidth-margin_Left-margin_Right)){float[] chayWidths = new float[textList[i].length()];textPaint.getTextWidths(textList[i],0,textList[i].length(),chayWidths);float rowTmpWidth = 0f;int startIdx = 0;for(int j=0;j<chayWidths.length;j++){if(rowTmpWidth+chayWidths[j]>(parentWidth-margin_Left-margin_Right)){ //如果加上当前的字符,超过父控件宽度了。则不加当前控件,换行TxtRowInfo item = new TxtRowInfo();item.rowText = textList[i].substring(startIdx,j);item.rowWidth = rowTmpWidth;item.startTop = totalHeight;drawTextList.add(item);maxWidth = Math.max(maxWidth,rowTmpWidth); //得到最大宽度totalHeight+=(txtHeight+ROW_SPACE); //增加行高度rowTmpWidth = chayWidths[j]; //重新计算新行宽度startIdx = j;//保存换行的起始字符}else{rowTmpWidth+=chayWidths[j];}}TxtRowInfo item = new TxtRowInfo();item.rowText = textList[i].substring(startIdx);item.rowWidth = rowTmpWidth;item.startTop = totalHeight;drawTextList.add(item);maxWidth = Math.max(maxWidth,rowTmpWidth); //得到最大宽度totalHeight+=(txtHeight+ROW_SPACE); //增加行高度}else{TxtRowInfo info = new TxtRowInfo();info.rowText = textList[i];info.rowWidth = rawWidth;info.startTop = totalHeight;drawTextList.add(info);totalHeight +=(txtHeight+ROW_SPACE);maxWidth = Math.max(maxWidth,rawWidth); //得到最大宽度}}totalHeight = totalHeight+pfm.ascent-ROW_SPACE; //此处要减去开始直接设置的文字top值与ascent的差值,保持上面文字边缘空白相同totalHeight += margin_Bottom; //加上下面要保留的空隙updateDrawTextLeft(maxWidth);textRect.set(0,0,margin_Left+maxWidth+margin_Right,totalHeight); //保存文字显示区域}else{if(drawTextList!=null){drawTextList.clear();drawTextList = null;}}}

VerticalPoster

本类实现了文字的竖向排版,其子类也是实现了装饰线效果、跳动文字效果等。核心函数

public void updateTextRect(int parentWidth, int parentHeight) {Log.d("Poster","------------updateTextRect-----------");if(textList!=null&&textList.length>0){if(drawTextList==null){drawTextList = new ArrayList<TxtRowInfo>(128); //默认设置是歌词行数2倍,不能每个都换行吧!}drawTextList.clear();Paint.FontMetrics pfm = textPaint.getFontMetrics();txtHeight = pfm.bottom-pfm.top; //保存现有字号下单个字的高度maxHeight = 0;//保存最大高度float maxRowWidth = textPaint.measureText("国"); //默认最宽的字符就是中文,数字与字母都比中文窄float startLeft = 0;float startTop =ROW_SPACE+(-pfm.top);int colCount = 1; //默认肯定有第一列float totalWidth=0; //保存总高度for(int i=0;i<textList.length;i++){float[] rawWidths = new float[textList[i].length()];//保存每一行的每个字符的宽度数组textPaint.getTextWidths(textList[i],rawWidths);int rawNo = 0; //记录换行的个数for(int j=0;j<textList[i].length();j++){startLeft = parentWidth - colCount*(maxRowWidth+COL_SPACE);startTop = ROW_SPACE+(-pfm.top) + (j-rawNo)*txtHeight;//因为top为负数,则要先取负再加上if((startTop+txtHeight)>parentHeight){ //如果测试发现下一个字符超过边界,则换行rawNo = j; //保存换行的这个字符indexupdateColHeight(colCount,(startTop+pfm.bottom+ROW_SPACE));colCount++;startTop = ROW_SPACE+(-pfm.top);startLeft = parentWidth - colCount*(maxRowWidth+COL_SPACE); //换列要重新计算一下}maxHeight = Math.max(maxHeight,(startTop+pfm.bottom+ROW_SPACE)); //保存最高的列,用于更新字符RectTxtRowInfo item = new TxtRowInfo();item.rowText = String.valueOf(textList[i].charAt(j));item.startLeft = startLeft+(maxRowWidth-rawWidths[j])/2; //把窄的字符要居中,所以这里要处理起点item.startTop = startTop;item.colIndex = colCount; //保存此字所在列位置,用于列对齐时更新起点做条件item.rowWidth = rawWidths[j];drawTextList.add(item);}updateColHeight(colCount,(startTop+pfm.bottom+ROW_SPACE));colCount++;}totalWidth = (colCount-1)*(maxRowWidth+COL_SPACE)+COL_SPACE; //此处要加上最左一行左边的空白区域updateDrawTextTop(maxHeight);updateVerTextLeft(parentWidth,totalWidth);textRect.set(0,0,totalWidth,maxHeight); //保存文字显示区域}else{if(drawTextList!=null){drawTextList.clear();drawTextList = null;}}}

DiffSizePoster

本类实现多行文字时,各行等宽、字体大小不同的混合排版效果。

核心函数:

public void updateTextRect(int parentWidth, int parentHeight) {if(textList!=null&&textList.length>0){if(drawTextList==null){drawTextList = new ArrayList<DiffRowInfo>();}drawTextList.clear();float totalHeight = 0;for(int i=0;i<textList.length;i++){float curTextSize = textPaint.getTextSize();float rowTotalWidth = textPaint.measureText(textList[i]);if(rowTotalWidth>parentWidth){//缩小字号,直到小于父控件while (rowTotalWidth>parentWidth){textPaint.setTextSize(--curTextSize);rowTotalWidth = textPaint.measureText(textList[i]);}}else{//扩大字号,直到大于父控件,然后获取前一字号值while (rowTotalWidth<parentWidth){textPaint.setTextSize(++curTextSize);rowTotalWidth = textPaint.measureText(textList[i]);}curTextSize--; //大于时才循环停止,所以这里要再减去最后大于的字号值,还原到小于宽度范围内textPaint.setTextSize(curTextSize);rowTotalWidth = textPaint.measureText(textList[i]);}//float maxRowWidth = textPaint.measureText("国"); //保存每个汉字标准的宽度float maxRowHeight = textPaint.getFontMetrics().bottom - textPaint.getFontMetrics().top;float totoalWidth = 0;if(totalHeight<0.1f){totalHeight += (maxRowHeight-(textPaint.getFontMetrics().bottom)); //保存上面所有行高,用于本行的top定位,因为文字的baseline在文字中下部,所以这里现减去bottom值,把y定位到baseline上}else{totalHeight += (maxRowHeight-(textPaint.getFontMetrics().bottom)+HEIGHT_SPACE); //保存上面所有行高,用于本行的top定位,因为文字的baseline在文字中下部,所以这里现减去bottom值,把y定位到baseline上}if(totalHeight>parentHeight){break;}float[] rowWidths = new float[textList[i].length()]; //保存每个字符的宽度,textPaint.getTextWidths(textList[i],rowWidths);float leftOffet = (parentWidth-rowTotalWidth)/2; //保存宽度差的一半,做为行首偏移量,实现居中效果for(int j=0;j<textList[i].length();j++){DiffRowInfo item = new DiffRowInfo();item.rowText = ""+textList[i].charAt(j);item.startTop =totalHeight; //item.startLeft = leftOffet + totoalWidth;item.fontSize = curTextSize;drawTextList.add(item);totoalWidth += rowWidths[j];}}totalHeight = Math.min(totalHeight+textPaint.getFontMetrics().bottom+HEIGHT_SPACE,parentHeight); //最高不能高过父控件高度textRect.set(0,0,parentWidth,totalHeight);}else{if(drawTextList!=null){drawTextList.clear();drawTextList = null;}}}

BmpDrawer

本类主要是用于绘制背景时,可设置ColorMatrix,达到改变图像颜色效果

核心代码是:

bgPaint.setColorFilter(new ColorMatrixColorFilter(bgColorMatrix));

同时模仿系统ImageView,支持了几种ScaleType的绘制

更多细节请去github上查看代码

本控件因为工作项目需要编写,功能比较独立、所以分享出来,希望能抛砖引玉,大牛们要是看到在结构上有不合理的地方,多指点:)

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。