由于Kuix作者设计理念的影响,所有的widget宽度都是自动增长的,除非它的宽度超过屏幕的宽度,实际上这种做法和一般设计时设定控件宽度的模式格格不入,而且经常性的,会出现输入框(textfield)超出屏幕边界的恶性效果,本文旨在讨论widget的长度是如何控制的,什么时候系统会自动计算窗口的布局情况。
widget虽然后width属性,但是它是不可以赋值的,这一点在修改TextArea中文断行时一直对它颇为迷惑。实际上直接查找Widget的width什么时候被修改是有些困难的,setBounds函数似乎是有这个效果,而且是共用的,实际上它只在Desktop中被调用,用于设置窗口或者说系统屏幕的大小。实际上所有控件的大小都是基于其中所包含的子控件的大小,而最终都基于Text的width,实际上Text的width则是在getPreferredSize计算出来,调用顺序为,需要刷新时,执行layou.dolayout>measure>getPreferredSize,当然不同的layout具体计算位置的算法有所不同。
/* (non-Javadoc) * @see org.kalmeo.kuix.widget.Widget#getPreferredSize(int) */ public Metrics getPreferredSize(int preferredWidth) { Metrics metrics; if (needToComputePreferredSize(preferredWidth)) { metrics = super.getPreferredSize(preferredWidth); String text = getText(); Font font = getFont(); if (font != null) { if (text != null) { metrics.width += font.stringWidth(text); } else { metrics.width += font.charWidth(' '); } metrics.height += font.getHeight(); } } else { metrics = getCachedMetrics(); } return metrics; }
当某个widget修改大小或者包含widget时,比如,text.setText,执行顺序如下settext>invalidate>parent.invalidate,逐级向上调用invalidate直到Desktop,调用KuixCanvas.revalidateNextFrame,读过《关于Kuix的窗口刷新机制》可以知道,此时会等待worker线程执行forceRevalidate>desktop.revalidate()>doLayout进行重新计算布局,进而调用forceRepaint重绘窗口
public boolean run() { if (needToChangeSize) { forceSizeChanged(desiredWidth, desiredHeight); } if (sizeInitialized) { // Key events, Pointer events and revalidation are execute only if transition is not running if (!transitionRunning) { // Key events if (!keyEvents.isEmpty()) { synchronized (this) { for (int i = 0; i < keyEvents.size(); ++i) { int[] keyEvent = ((int[]) keyEvents.elementAt(i)); FocusManager focusManager = desktop.getCurrentFocusManager(); if (focusManager != null && focusManager.processKeyEvent((byte) keyEvent[0], keyEvent[1])) { repaintNextFrame(); } } } keyEvents.removeAllElements(); } // Pointer events if (!pointerEvents.isEmpty()) { synchronized (this) { for (int i = 0; i < pointerEvents.size(); ++i) { int[] pointerEvent = ((int[]) pointerEvents.elementAt(i)); FocusManager focusManager = desktop.getCurrentFocusManager(); if (focusManager != null && focusManager.processPointerEvent((byte) pointerEvent[0], pointerEvent[1], pointerEvent[2])) { repaintNextFrame(); } else if ((byte) pointerEvent[0] == KuixConstants.POINTER_DROPPED_EVENT_TYPE) { if (desktop.getDraggedWidget() != null) { desktop.removeDraggedWidget(true); } } } } pointerEvents.removeAllElements(); } // Revalidate if needed if (needToRevalidate) { forceRevalidate(); } } // Repaint if (needToRepaint) { forceRepaint(); } } return false; } };实际上要设定控件的固定宽度,最好是从widget的底层修改,增加fixWidth属性,在属性有赋值时强制固定大小,并且针对性的对于继承的控件。
package org.yexing.mapdemos; GraphicOverlay.java import android.graphics.Canvas; //import android.graphics.Paint; //import android.graphics.RectF; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.view.MotionEvent; import com.google.android.maps.Overlay; import com.google.android.maps.Point; public class GraphicOverlay extends Overlay { BitmapDrawable bmp; static int w, h; Point p; public GraphicOverlay(Drawable d, Point p) { bmp = (BitmapDrawable) d; this.p = p; w = bmp.getIntrinsicWidth(); h = bmp.getIntrinsicHeight(); } public void draw(Canvas canvas, PixelCalculator calculator, boolean shadow) { calculator.getPointXY(p, sXYCoords); bmp.setBounds(sXYCoords[0] - w / 2, sXYCoords[1] - h, sXYCoords[0] + w / 2, sXYCoords[1]); bmp.setAlpha(70); bmp.draw(canvas); /* RectF oval = new RectF(xyCoords[0], xyCoords[1], xyCoords[0] + 5, xyCoords[1] + 5); Paint paint = new Paint(); paint.setARGB(200, 255, 0, 0); canvas.drawOval(oval, paint); */ } public Point getCenter() { return p; } public boolean dispatchMotionEvent(MotionEvent ev) { return false; } }
在引用的时候把一个activity作为参数传进
public GraphicOverlay(Activity map) { mMap = map; ... }
bmp = mMap.getIcon("name")
Point p = mMap.getCurrentLocation()
或者
nMap = map;
fav_icon = (BitmapDrawable)
mMap.getResources().getDrawable(R.drawable.cake);
锁定 Activity 运行时的屏幕方向
<activity android:name=".EX01" android:label="@string/app_name" android:screenOrientation="portrait" // 竖屏 , 值为 landscape 时为横屏 ………… </activity>
全屏的 Activity
要使一个 Activity 全屏运行,可以在其 onCreate()方法中添加如下代码实现:
// 设置全屏模式 getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); // 去除标题栏 requestWindowFeature(Window.FEATURE_NO_TITLE);
在 Activity 的 Title 中加入进度条
在 Activity 的标题栏中显示进度条不失为一个好办法,下面是实现代码:
// 不明确进度条 requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS); setContentView(R.layout.main); setProgressBarIndeterminateVisibility(true); // 明确进度条 requestWindowFeature(Window.FEATURE_PROGRESS); setContentView(R.layout.main); setProgress(5000);