怎么让Canvas子css 控件右对齐齐

2.3.3 文字的对齐方式
本文所属图书&>&
本书主要讲解使用HTML5 Canvas来开发和设计各类常见游戏的思路和技巧,在介绍HTML5 Canvas相关特性的同时,还通过游戏开发实例深入剖析了其内在原理,让读者不仅知其然,而且知其所以然。在本书中,除了介绍了...&&
Canvas中的文字通过textAlign和textBaseline来实现文字的对齐。textAlign是水平方向的文字对齐,它的值包括center、end、left、right、start。textBaseline是竖直方向的文字对齐,它的值包括alphabetic、bottom、hanging、ideographic、middle、top。
首先看水平方向的对齐。为了看出不同的对齐方式之间的区别,我们在文字坐标位置画一条竖线,如代码清单2-21所示。
代码清单 2-21
&script type=&text/javascript&&
var c=document.getElementById(&myCanvas&);
var ctx=c.getContext(&2d&);
ctx.moveTo(160,0);
ctx.lineTo(160,300);
ctx.stroke();
ctx.beginPath();
ctx.textAlign='start';
ctx.font='30px Arial';
ctx.fillText(&Hello World&,160,50);
ctx.beginPath();
ctx.textAlign='end';
ctx.font='30px Arial';
ctx.fillText(&Hello World&,160,100);
ctx.beginPath();
ctx.textAlign='left';
ctx.font='30px Arial';
ctx.fillText(&Hello World&,160,150);
ctx.beginPath();
ctx.textAlign='center';
ctx.font='30px Arial';
ctx.fillText(&Hello World&,160,200);
ctx.beginPath();
ctx.textAlign='right';
ctx.font='30px Arial';
ctx.fillText(&Hello World&,160,250);
运行效果如图2-24所示。
可以看到,start与left相同,表示文字从左侧开始对齐;end与right相同,表示文字从右侧开始对齐,center表示文字居中。
接下来看竖直方向的对齐。同样,为了看出不同的对齐方式之间的区别,我们在文字坐标位置画一条横线,如代码清单2-22所示。
代码清单 2-22
&script type=&text/javascript&&
var c=document.getElementById('myCanvas');
var ctx=c.getContext('2d');
ctx.textBaseline='alphabetic';
ctx.font='30px Arial';
ctx.fillText('Hello World',50,50);
ctx.moveTo(0,50);
ctx.lineTo(250,50);
ctx.stroke();
ctx.textBaseline='bottom';
ctx.font='30px Arial';
ctx.fillText('Hello World',50,100);
ctx.moveTo(0,100);
ctx.lineTo(250,100);
ctx.stroke();
ctx.textBaseline='hanging';
ctx.font='30px Arial';
ctx.fillText('Hello World',50,150);
ctx.moveTo(0,150);
ctx.lineTo(250,150);
ctx.stroke();
ctx.textBaseline='ideographic';
ctx.font='30px Arial';
ctx.fillText('Hello World',50,200);
ctx.moveTo(0,200);
ctx.lineTo(250,200);
ctx.stroke();
ctx.textBaseline='middle';
ctx.font='30px Arial';
ctx.fillText('Hello World',50,250);
ctx.moveTo(0,250);
ctx.lineTo(250,250);
ctx.stroke();
ctx.textBaseline='top';
ctx.font='30px Arial';
ctx.fillText('Hello World',50,300);
ctx.moveTo(0,300);
ctx.lineTo(250,300);
ctx.stroke();
运行效果如图2-25所示。
图2-25所示很清晰地体现了竖直方向的各个对齐方式的区别。
您对本文章有什么意见或着疑问吗?请到您的关注和建议是我们前行的参考和动力&&
(window.slotbydup=window.slotbydup || []).push({
id: '2467141',
container: s,
size: '1000,90',
display: 'inlay-fix'
您的浏览器不支持嵌入式框架,或者当前配置为不显示嵌入式框架。
(window.slotbydup=window.slotbydup || []).push({
id: '2467142',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467143',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467148',
container: s,
size: '1000,90',
display: 'inlay-fix'自定义控件其实很简单(9)
尊重原创转载请注明:From AigeStudio(http://blog.csdn.net/aigestudio)Power by Aige 侵权必究!
隐约雷鸣 阴霾天空 但盼风雨来 能留你在此
隐约雷鸣 阴霾天空 即使天无雨 我亦留此地
上一节我们细致地、猥琐地、小心翼翼地、犹如丝滑般抚摸、啊不,是讲解了如何去测量一个布局控件,再次强调,如我之前多次强调那样,控件的测量必须要逻辑缜密严谨,尽量少地避免出现较大的逻辑错误。在整个系列撰写的过程中,有N^N个朋友曾多次不间断地小窗我问View是否也有生命周期,我也多次细心地、耐心地打开小窗然后默默地关掉它,不是我不愿回答而是问的人太多我们干脆就在blog中详细阐述下,即便你是第一天学习Android,你也一定会用到Activity,用到Activity你一定会接触到onCreate方法,然后你会从各种途径了解到类似这样的方法还有7个,我们称之为Activity生命周期:
Android framework在Activity的不同时期调用不同的生命周期方法并将其提供给我们以便我们能在Activity加载的不同时期根据自己的需要做不同的事,For example:我们可以在onCreate中设置我们的布局文件或显示的View,在onStop中处理Activity位于后台时的操作,在onDestroy中销毁一些不必要的强引用避免在Activity销毁后造成泄漏等等等等,这些方法给我们控制Activity带来了极大的便利,而在View中我们也学习了onMeasure、onLayout和onDraw这三个类似的方法,它们也是依次在View创建的不同时期被调用,那么是否还应存在其他类似的方法呢?The
answer is yes,View也提供了一下几个类似“生命周期”的方法:
如上所示的这些方法,除了提到的“生命周期”方法外还有一些事件的回调,多说无益,我们还是来看看这些方法会在View的什么时候被调用,老样子我们新建一个继承于View的子类并重写这些方法:
上面的方法中我过滤掉了事件和焦点触发的方法,仅看View运行时被调用的方法,运行看看我们LogCat中的输出:
首先是调用了构造方法,这是不用猜都该知道的,然后呢调用了onFinishInflate方法,这个方法当xml布局中我们的View被解析完成后则会调用,具体的实现在LayoutInflater的rInflate方法中:
也就是说如果我们不从xml布局文件中解析的话,该方法就不会被调用,我们在Activity直接加载View的实例:
这时再次运行我们的APP,就会发现不会再去调用onFinishInflate方法:
紧接着调用的是onAttachedToWindow方法,此时表示我们的View已被创建并添加到了窗口Window中,该方法后紧接着一般会调用onWindowVisibilityChanged方法,只要我们当前的Window窗口中View的可见状态发生改变都会被触发,这时View是被显示了,随后就会开始调用onMeasure方法对View进行测量,如果测量结果被确定则会先调用onSizeChanged方法通知View尺寸大小发生了改变,紧跟着便会调用onLayout方法对子元素进行定位布局,然后再次调用onMeasure方法对View进行二次测量,如果测量值与上一次相同则不再调用onSizeChanged方法,接着再次调用onLayout方法,如果测量过程结束,则会调用onDraw方法绘制View。我们看到,onMeasure和onLayout方法被调用了两次,很多童鞋会很纠结为何onMeasure方法回被多次调用,其实没必要过于纠结这个问题,onMeasure的调用取决于控件的父容器以及View
Tree的结构,不同的父容器有不同的测量逻辑,比如上一节中,我们在SquareLayout测量子元素时就采取了二次测量,在API 19的时候Android对测量逻辑做了进一步的优化,比如在19之前只会对最后一次的测量结果进行Cache而在19开始则会对每一次测量结果都进行Cache,如果相同的代码相同布局相同的逻辑在19和19之前你有可能会看到不一样的测量次数结果,所以没必要去纠结这个问题,一般情况下只要你逻辑正确onMeasure都会得到正确的调用。
上面这些方法都很好理解,我们主要关心的是其调用流程,虽然上面我们通过LogCat的输出大致了解了一下其执行顺序,但是如果你好奇心足够重,一定会想真是这样的么?在中我曾留下一个疑问:
就是如上代码片段是否有什么问题?细心的盆友其实已经发现了,我们在onDraw中用到的mBitmap竟不为null,按照我们上面分析的结果,如果顺次调用View的各个方法,那么此时如果我们在Activity中调用setBitmap方法为我们的ImgView设置Bitmap:
的话onDraw方法获取到的Bitmap应该为null才对,或者直白地说setBitmap方法应该在onDraw之后才被调用才对。对么?如果你这样想,别说Android,甚至连Java基础都不过关~~~为什么这么说呢?记住上面这些除了构造方法外的onXXX方法,都是一系列的回调方法,当且仅当一定条件成立才会被触发,比如上面说过的onFinishInflate方法,只有在该View以及其子View从xml解析完毕才会被调用,打个比方,如果我们编译Android源代码,尝试在rInflate方法解析完xml生前View调用onFinishInflate之前调用我们的setBitmap方法,这时候你就会看到执行顺序的改变。具体的原理设计太多的framework源码,在该系列我就不在多贴一些系统的源码了,如果你想更深地了解,我会在后续的《深入剖析Android
GUI框架》系列中详细阐述,这里我仅作简单的介绍,注意到上面我在说View的“生命周期”时使用了一个引号,虽然说到上面的一些方法会在View运行过程中依次被调用,但事实上真正称得上View的生命周期的阶段只有三个:
处理控件动画的阶段处理测量的阶段处理绘制的阶段
Android的Animation动画体系庞大不在本系列的讲解范畴内,暂时Skip,测量和绘制的主要过程由我们之前所讲的三个方法onMeasure、onLayout和onDraw所控制,这三个方法呢在framework中又主要由measure、layout、draw以及其派生方法所控制,在View中形成这样一个体系:
再次注意:View的测量过程是由多个方法调用共同构成,measure和onMeasure仅仅代表该过程中的两个方法而已。
如果控件继承于ViewGroup实现的是一个布局容器,那么会多出一个dispatchDraw方法:
dispatchDraw方法本质上实现的是父容器对子元素的绘制分发,虽然逻辑不尽相同但是作用类似于draw,在中我们曾利用该方法在绘制子元素前绘制盖楼背景,具体不再多说了。在我们调用setContentView方法后,如果你传入的是一个资源文件ID,此时framework会使用LayoutInflater去解析布局文件,当解析到我们自定义控件LifeCycleView的标签时,通过反射获取一个对应的LifeCycleView类实例,此时构造方法被调用,尔后开始解析LifeCycleView标签下的各类属性并存值,LifeCycleView标签下的所有属性(如果是个容器的话也会层层解析)解析完成后调用onFinishInflate方法表示当前LifeCycleView所有的(注意不是整个布局哦仅仅是该View对应标签)xml解析完毕,之后尝试将View添加至当前Activity所在的Window,然后将处理UI事件的Msg压入Message
Queue开始至上而下地对整个View Tree进行测量,假设我们有如下的View Tree结构:
那么我们的测量总是从根部RelativeLayout开始逐层往下进行调用,在中我们曾在讲滑动时对Message Queue作过一个简单的浅析,当Msg压入Queue并最终得到处理的这段过程并不是立即的,也就是说其中会有一定的延时,这相对于我们在setContentView后立即setBitmap来说时间要长很多很多,这也是为什么我们在onMeasure中获取Bitmap不为null的原因,具体的源码逻辑实现会在《深入剖析Android
GUI框架》深度讲解,本系列除了后面要涉及到的事件分发外不会再涉及过多的源码毕竟与基础篇的定位不符,好了,这里我再留一个问题,setBitmap和onMeasure、onLayout等这些回调方法之间是异步呢还是同步呢?其实答案很明显了……OK,不说了,既然我们知道这样直接setBitmap是不对的(即便可行)那么我们该如何改进呢?答案很简单,Andorid提供给我们极其简便的方法,我们只需在设置Bitmap后调用requestLayout方法和invalidate即可:
requestLayout方法的意义在于如果你的操作有可能会让控件的尺寸或位置发生改变那么就可以调用该方法请求布局,调用该方法后framework会尝试调用measure对控件重新测量:
而invalidate方法呢我们则用的多了不再多说:
但是要注意的一点是,requestLayout方法和invalidate方法并非都必需调用的,比如我们有一个更改字体颜色的方法:
这时我们仅需调用invalidate方法标识重绘视图即可,但是,如上我们所说,如果一旦尺寸大小或位置发生了变化,那么我们最好重新布局并迫使视图重绘,比如我们有个改变字体大小的方法:
这时候我们就需要调用requestLayout请求布局,因为字体大小的改变有可能会影响到控件的尺寸大小和位置的改变,同样,如果位置大小都变了,那我们是否该重新绘制呢?The answer is yes~好了,别嫌我啰嗦,最近有盆友反应说前面章节太难理解……其实之所以觉得前面的章节难是因为涉及绘制的API大多跟一些图像处理有关,而coder正恰恰缺乏这方面的一些知识所以不好理解,你看我前面的章节压根就没涉及什么源码,只有从测量开始才涉及了一次,此后也不再打算再过多地涉及,毕竟与该系列基础篇的定位不符。闲话不多说了,如上以及前面两节的内容所述,其实在应用开发使用的过程中设计测量逻辑的API并不多,也没太多可讲的,最主要的还是自己的逻辑,So,这一部分暂且为止,在中我们曾定义过一个类似图标的控件:
当时我们是直接extends View去做的,绘制了文本、绘制了Bitmap还有在此之前对其进行测量、定位等等,即便我们考虑周详,但是也极难将一个装载文本和图片的控件做成一个TextView和ImageView的复合体,更难以像TextView和ImageView那样提供尽可能多的接口方法,诶!等等!既然我们的这个图标控件看上去就是个TextView和ImageView杂交的后代,那么我们是否可以简单地将这两种控件组合起来变成一个新的控件呢?答案是肯定的撒!而且比起我们直接extends view来说简单很多很多很多,首先我们先定义一个布局,这个布局里面呢只包含一个ImageView和一个TextView,大体来说样式跟上面我们自定义的类似:
ADT中直接展示的效果如下:
是不是跟我们自定义的一样呢?如我所说,仅仅是一个ImageView和TextView的组合而已,接下来我们要做的则是将这个xml布局文件“集成”到我们的自定义控件中去,方法也很简单,在自定义控件的构造方法里引入该布局文件并将其作为控件的布局则可:
上面的代码中我选择继承了FrameLayout,实际上你可以选择继承任何一种布局容器类,关键在于我们加载xml布局文件时以该布局容器作为根布局:
“this”就表示了将整个xml布局文件作为子元素加载至ComplexView(extends FrameLayout)下,构成如下图所示的一个层级关系:
而后我们只需直接使用这个ComplexView符合控件即可:
这时候就可以直接在ADT中查看效果:
非常完美,不需要我们去处理测绘逻辑,所有的这些都由Android自带的控件自行去计算,我们只是简单地将它们组合在一起了而已,所以说,每当Android提供的控件不能满足你的需求时,首先你应该想想是否可以在现有控件的基础上修改一下来达到你的目的,而不是盲目地直接重写View或ViewGroup类,你可以提供不同的接口方法来修改你复合控件中的各类元素,比如下面我们提供一个setImageIcon方法来为复合控件中的ImageView设置图片:
你甚至可以直接提供一个getter方法去获取复合元素的引用:
这样你就可以对复合控件中的TextView为所欲为了……如前几节我们所说,framework对xml文件的解析是相当耗时的,如果可以,我们应当尽量避免对xml文档的读取,特别是元素结构复杂的xml文件,这里我们用到的xml布局文件还不算复杂,如果我不想从xml文档读取而是直接实例化类呢?我们来重新修改下我们的代码:
直接让复合控件类继承LinearLayout,在构造方法中实例化子元素并设置其属性值然后添加至LinearLayout中搞定,复合控件在实际应用中也使用得相当广泛,因为很多时候使用符合控件不需要处理复杂的测绘逻辑,简单方便高效。在Android自带的控件中有个checkBox复选框控件:
效果单一乏味不好看,而我想要的效果很简单也与之类似,通过不断点击控件往复切换控件的两种状态即可:
达到类似效果有多种方法,最简单的是更改checkBox,最复杂的是继承View自己写一个,而上面我们了解过复合控件,那么我们能不能马上学以致用使用一个复合控件来达到该效果呢?答案是肯定的!细心观察可以看得出上面的效果无非就是两张不同的图片来回显示/隐藏地切换而已,更直白地说就是两个ImageView不断地显示/隐藏切换对吧,Such easy,下面直接看全部代码:
整个复合控件非常简单,我们只是简单地将两个ImageView重叠组合了在一起并设置其点击事件监听,对外我们公布了一个CustomCheckBoxChangeListener监听接口以监听状态的改变并处理一些逻辑,只需在Activity中获取CustomCheckBox控件并设置监听对象即可:
当CustomCheckBox的当前状态为未被选中时会触发customCheckBoxOff方法否则触发customCheckBoxOn方法:
CustomCheckBox中加载用到的xml布局文件如下:
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:24518次
排名:千里之外
原创:28篇
转载:69篇
微博:古道Galio
(3)(1)(11)(1)(1)(1)(32)(3)(1)(1)(4)(2)(12)(10)(12)经常会遇到要在Canvas里将各类控件居中的问题,下面以TextBlock为例说明。
//在将TextBlock添加到Canvas前获取它的实际尺寸
TextBlock label = new TextB
label.Text = "It is a test";
label.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
Size labelSize = label.DesiredS
Canvas canvas = new Canvas();
canvas.Width = 100;
canvas.Height = 40;
canvas.Children.Add(label);
Canvas.SetLeft(label, (canvas.Width - labelSize.Width)/2);
Canvas.SetTop(label, (canvas.Height - labelSize.Height)/2);
阅读(...) 评论()网页设计教程与开发
提供各种常见网页效果
提供各种各样的设计教程
装扮QQ,让QQ变得更酷
设计参考,提高自升水平
学习服务器和操作系统
提供各种素材和工具
收藏学习资料
您现在的位置:&&>>&&>>&&>>&&>>&正文
HTML5教程:HTML5 Canvas的文本对齐
破洛洛文章简介:要对齐HTML5 Canvas的文本,我们可以使用画布的背景下textAlign属性,可以设置居上,底下,居左,中心,或居右。对齐方式是相对的,以一个假想的x位置由defind文本的垂直线fillText( )或strokeText( )。除非另有设置,TextAlign属性默认为左,这不禁让我们想起了css
要对齐HTML5 Canvas的文本,我们可以使用画布的背景下textAlign属性,可以设置居上,底下,居左,中心,或居右。对齐方式是相对的,以一个假想的x位置由defind文本的垂直线fillText( )或strokeText( )。除非另有设置,TextAlign属性默认为左,这不禁让我们想起了css属性中的text-align
context.textAlign=[value];
window.onload = function(){&
&&& var canvas = document.getElementById(&myCanvas&);&
&&& var context = canvas.getContext(&2d&);&
&&& var x = canvas.width / 2;&
&&& var y = canvas.height / 2;&
&&& context.font = &30pt Calibri&;&
&&& context.textAlign = &center&;&
&&& context.fillStyle = &blue&;&
&&& context.fillText(&Hello World!&, x, y);&
转载请注明:破洛洛(谢谢合作)
上一篇文章: 下一篇文章:
网友评论:
[][][][][][][][][][]AWT Canvas类
AWT Canvas类
Windows10用户联盟QQ群:
Canvas控件代表一个矩形区域,应用程序可以画的东西,或者可以由用户创建的接收输入。
以下是声明的java.awt.Canvas类:
public class Canvas
extends Component
implements Accessible
类的构造函数
构造函数& 描述
Constructs a new Canvas.
Canvas(GraphicsConfiguration config)&
Constructs a new Canvas given a GraphicsConfiguration object.
方法& 描述
void addNotify()&
Creates the peer of the canvas.
void createBufferStrategy(int numBuffers)&
Creates a new strategy for multi-buffering on this component.
void createBufferStrategy(int numBuffers, BufferCapabilities caps)&
Creates a new strategy for multi-buffering on this component with the required buffer capabilities.
AccessibleContext getAccessibleContext()&
Gets the AccessibleContext associated with this Canvas.
BufferStrategy getBufferStrategy()&
Returns the BufferStrategy used by this component.
void paint(Graphics g)&
Paints this canvas.
void pdate(Graphics g)&
Updates this canvas.
继承的方法
这个类继承的方法从以下类:
java.lang.Object
Canvas 实例
选择使用任何编辑器创建以下java程序&D:/ & AWT & com & yiibai & gui &
AwtControlDemo.java
package com.yiibai.gui;
import java.awt.*;
import java.awt.event.*;
public class AwtControlDemo {
private Frame mainFrame;
private Label headerLabel;
private Label statusLabel;
private Panel controlPanel;
public AwtControlDemo(){
prepareGUI();
public static void main(String[] args){
AwtControlDemo
awtControlDemo = new AwtControlDemo();
awtControlDemo.showCanvasDemo();
private void prepareGUI(){
mainFrame = new Frame(&Java AWT Examples&);
mainFrame.setSize(400,400);
mainFrame.setLayout(new GridLayout(3, 1));
mainFrame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent windowEvent){
System.exit(0);
headerLabel = new Label();
headerLabel.setAlignment(Label.CENTER);
statusLabel = new Label();
statusLabel.setAlignment(Label.CENTER);
statusLabel.setSize(350,100);
controlPanel = new Panel();
controlPanel.setLayout(new FlowLayout());
mainFrame.add(headerLabel);
mainFrame.add(controlPanel);
mainFrame.add(statusLabel);
mainFrame.setVisible(true);
private void showCanvasDemo(){
headerLabel.setText(&Control in action: Canvas&);
controlPanel.add(new MyCanvas());
mainFrame.setVisible(true);
class MyCanvas extends Canvas {
public MyCanvas () {
setBackground (Color.GRAY);
setSize(300, 300);
public void paint (Graphics g) {
Graphics2D g2;
g2 = (Graphics2D) g;
g2.drawString (&It is a custom canvas area&, 70, 70);
编译程序,使用命令提示符。到&D:/ & AWT&然后键入以下命令。
D:AWT&javac comyiibaiguiAwtControlDemo.java
如果没有错误出现,这意味着编译成功。使用下面的命令来运行程序。
D:AWT&java com.yiibai.gui.AwtControlDemo
验证下面的输出
标签:&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&}

我要回帖

更多关于 安卓控件右对齐 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信