Android图片海报制作-自定义文字排版控件组件
来源:互联网 发布:山东税务软件下载 编辑:程序博客网 时间:2024/05/01 21:26
项目地址:https://github.com/coolstar1204/MakePoster
今天主要讲一下项目主要控件,文字排版控件组,实现类似QQ音乐歌词海报效果。
控件主要功能点
- 可设置背景图片
- 可设置标题文字,并支持标题文字自动居中、超长自动…
- 可设置图片颜色效果,实现黑白、旧照片、变暗、变亮等效果(有些效果还不太理想)
- 可增加多行自定义文字、支持文字设置阴影、颜色、大小、居中居右居左等对齐通用设置,支持文字特效
排版(横向、竖向、不同行等宽不同字体大小效果等)
控件设计结构
核心类
IPoster:字义了排版功能,直接子类有DiffSizePoster、HorizontalPoster、VerticalPoster三个类。
IBmpDrawer:定义了背景图绘制功能,实现类目前只有BmpDrawer,支持ColorMatrix设置
TextDrawer:控件基类,继承于View控件,内部管理上二个接口实现类、增加了标题栏和Logo的绘制功能、导出海报图片功能。
TextDrawer
核心函数有:
@Override protected void onDraw(Canvas canvas) { onDrawBackBmp(canvas); //画文字,文字位置使用scroll变量偏移,达到拖动效果 canvas.save(); canvas.translate(mScrollX,mScrollY); if(poster!=null){ poster.onPostDraw(canvas); } canvas.restore(); //画标题文字与酷我logo drawLogoAndTitle(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); outBmp.compress(Bitmap.CompressFormat.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; //保存换行的这个字符index updateColHeight(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)); //保存最高的列,用于更新字符Rect TxtRowInfo 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上查看代码
本控件因为工作项目需要编写,功能比较独立、所以分享出来,希望能抛砖引玉,大牛们要是看到在结构上有不合理的地方,多指点:)
0 0
- Android图片海报制作-自定义文字排版控件组件
- 自定义Android图片上加文字组件
- Android图片海报制作软件开发实践
- Android图片海报制作-MVP的使用
- Android图片海报制作-MaterialDesign使用
- android自定义控件Button 带图片文字
- Android自定义控件图片+文字布局
- 自定义View控件解决android文字排版和换行的问题
- 自定义View控件解决android文字排版和换行的问题
- Android自定义组件,实现图片和文字同时显示
- 如何制作图片和文字混合排版的word标题
- 自定义图片、文字组合控件
- Android自定义“图片+文字”控件四种实现方法
- 图片和文字排版
- 仿海报工厂效果的自定义View(在图片上输入文字)
- PHP合成推广微信推广海报 PHP合成图片 PHP在图片上添加文字 PHP制作图片
- 【工具】用PPT排版打印海报时图片分辨率问题
- 图片加文字的自定义控件
- Android之Notification
- 插入排序
- http://blog.csdn.net/olanlanxiari/article/details/8104505
- Mac常见问题解决
- Ubuntu下控制蜂鸣器
- Android图片海报制作-自定义文字排版控件组件
- 编程实现通过状态图确定句子
- 使用powershell Client进行有效dy
- 稀疏矩阵的压缩存储与转置
- XML基础解析<copy>
- s3c2440第一个流水灯驱动程序(JZ2440)
- EventBus3.0的使用
- 谁说理工男不浪漫?电子工程师的恋爱神器
- AC自动机+DP(POJ2778&&POJ3691)