Monday, October 26, 2009

Layout trick: use layout_weight to strech the view to fill up the screen

My intent was to put a ListView in the top of the screen, 2 buttons in the bottom of the screen.
I hope the 2 buttons could stay put at the bottom, no matter whether List was too short to fill the space left, or too long to have to be scrolled.

The trick was to use layout_weight="1" for the ListView.

<linearlayout android="http://schemas.android.com/apk/res/android" layout_width="fill_parent" layout_height="fill_parent" orientation="vertical">
<listview id="@+id/lv_his_list" layout_width="fill_parent" layout_height="0dip" layout_weight="1" stackfrombottom="true" transcriptmode="normal" choicemode="singleChoice">

<tablelayout layout_width="fill_parent" layout_height="wrap_content" stretchcolumns="0,1">
<tablerow>
<button style="" id="@+id/btn_his_list_modify" text="@string/modify_str">

</button></tablerow>
</tablelayout>

</listview>

Another testing of mine was for TableLayout, it also made sense.

Wednesday, March 18, 2009

Marquee feature of TextView in Android 1.1R1

In the newest release, Android 1.1 R1, android.widget.TextView begins to support marquee feature.
It provides a value, marquee, for android:ellipsize, and a new attribute, android:marqueeRepeatLimit.

However you could not make the TextView scrolling if you only set these 2 attributes.
According to my testing, at least the following 3 attributes shall be set:
android:ellipsize="marquee"
android:focusable="true"
android:singleLine="true"
And the TextView shall be focused while running.

Moreover, I found 2 limitations in current marquee implementation:
  1. Never scroll if the TextView does not get the focuse;
  2. The scrolling is odd because the round of scrolling begins from the left side while end at the right side. It looks like the animation is reset.
So far, I think my implementation of ScrollTextView is better for the marquee feature. :)

Wednesday, March 11, 2009

Browse Android Java source codes online

Sometimes, it's necessary for developer to check the implementation of an API when the SDK documentation is not enough for understanding.
However, Android source codes are approximately 2.1G in size. It's not handy to download and browse them in local PC.
Fortunately, source.android.com supports GitWeb for web browsing of the source codes though it's not intuitive to find out which git ball the java code is in.
Some guy find out the path. It is
[platform/frameworks/base.git] / core / java /

Wednesday, March 4, 2009

Technical Key Points of Androidmine Project

Here are the techincal key points I learned from the open source project, androidmine.
Its current version is 0.7.

1. Customize the activity theme (window without title)
AndroidManifest.xml
<activity android:name=".Main" android:theme="@style/Theme.Game">
...
res/values/styles.xml
<style name="Theme.Game">
<item name="android:windowNoTitle">true</item>
</style>

2. Set the conent view for the activity
Use android.app.Activity.setContentView(View view) to set the activity content to an explicit view. This view is placed directly into the activity's view hierarchy. It can itself be a complex view hierarhcy. By this way, you can switch any view you want to show.
Overwrite onLayout, onDraw to customize the view
Overwrite onKeyUp, onKeyDown and onTouchEvent to handle the user input
Call invalidate in the UI thread, or postInvalidate in the non-UI thread to make the onDraw called

3. Use android.os.Handler to send and handle messages, schedule an action in the feature

4. Use android.media.MediaPlayer to play background music in a separated thread

Saturday, February 28, 2009

Dimension Values of Android API

The document of Android API 1.0 rc2
You can create common dimensions to use for various screen elements by defining dimension values in XML. A dimension resource is a number followed by a unit of measurement. For example: 10px, 2in, 5sp. Here are the units of measurement supported by Android:
px
Pixels - corresponds to actual pixels on the screen.
in
Inches - based on the physical size of the screen.
mm
Millimeters - based on the physical size of the screen.
pt
Points - 1/72 of an inch based on the physical size of the screen.
dp
Density-independent Pixels - an abstract unit that is based on the physical density of the screen. These units are relative to a 160 dpi screen, so one dp is one pixel on a 160 dpi screen. The ratio of dp-to-pixel will change with the screen density, but not necessarily in direct proportion. Note: The compiler accepts both "dip" and "dp", though "dp" is more consistent with "sp".
sp
Scale-independent Pixels - this is like the dp unit, but it is also scaled by the user's font size preference. It is recommend you use this unit when specifying font sizes, so they will be adjusted for both the screen density and user's preference.


My understanding
px, in, mm and pt are all absolute units.
px is based on the resolution of the screen.
in, mm and pt are based on the physical size of the screen.
dip/sp can accommodate size with the resolution to make it appear exactly the same size.

Here's the comment got from reply in the android developer group:
[Romain Guy]
If you specify, in your application, a button with a width of 100
pixels, it will look at lot smaller on the 640x480 device than on the
320x480 device. Now, if you specify the width of the button to be 100
dip, the button will appear to have exactly the same size on the two
devices.

You can easily see this happen when you compare the T-Mobile G1 with
the Android emulator. Computer monitors usually have low/medium pixel
densities. For instance, the monitor I'm using to write this email has
a density of about 100 pixels per inch, whereas the G1 has about 180
pixels per inch. This means that when I compare my application on the
G1 with my application on the Android emulator on my computer, the
version on my computer appears a lot bigger to me.

It is very important that you use resolution independent units like
dip when you create your UI. This well help make your application run
on future Android devices that may or may not have the same pixel
density as the G1.
If you specify, in your application, a button with a width of 100
pixels, it will look at lot smaller on the 640x480 device than on the
320x480 device. Now, if you specify the width of the button to be 100
dip, the button will appear to have exactly the same size on the two
devices.

You can easily see this happen when you compare the T-Mobile G1 with
the Android emulator. Computer monitors usually have low/medium pixel
densities. For instance, the monitor I'm using to write this email has
a density of about 100 pixels per inch, whereas the G1 has about 180
pixels per inch. This means that when I compare my application on the
G1 with my application on the Android emulator on my computer, the
version on my computer appears a lot bigger to me.

It is very important that you use resolution independent units like
dip when you create your UI. This well help make your application run
on future Android devices that may or may not have the same pixel
density as the G1.
The conclusion is that you should use dip/sp as many as possible unless you have solid reason to use the other dementions instead.
In development you can also telnet to the simulator (telnet localhost 5554) to use the 'window scale' command to change the screen density to verify if your application can accomadate with various screens.

References:
1. http://vod.sjtu.edu.cn/help/Article_Show.asp?ArticleID=308&ArticlePage=11.
2. http://baike.baidu.com/view/49853.html
3. http://fbljava.blog.163.com/blog/static/26521174200871383754608/#
4. http://groups.google.com/group/android-developers/browse_thread/thread/978813b2998ef439/f63e4e51bdb2e2d5#f63e4e51bdb2e2d5

Monday, January 12, 2009

find out the version of ksh/dtksh in Solaris

It took me quite some minutes to find out in Google how to find out the versions of ksh and dtksh in Solaris.

1. Start a shell
$ ksh
or
$ dtksh
2. Enter vi mod
$ set -o vi
Note: The option is letter 'o' , not number zero "0".
3. Press ESC to enter command mode
4. Press Ctrl-V

Here are outputs in Solaris 8 & 9
$ Version M-11/16/88
$ Version M-12/28/93

Tuesday, January 6, 2009

ScrollTextView - scrolling TextView for Android

I wrote a class derived from Android.Widget.TextView to customize a TextView which text can be scrolled.
The derived class, named ScrollTextView, provides an effect just like the HTML marquee tag.
Moreover, the scrolling can be restarted, paused and resumed.

Here are the source codes.

The key points are:
  • setHorizontallyScrolling() and use android.widget.Scroller to make the text scroll;
  • Use the attached TextPaint of the TextView to measure the length of the text in pixel;
  • setSingleLine() and setEllipsize(null) to make the text not wrapped and ellipsized;
  • Override computeScroll() to restart the scrolling when finished
Here are the source codes.

/*************************************************************************/
package com.dirtybear.android;

import android.content.Context;
import android.graphics.Rect;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.view.animation.LinearInterpolator;
import android.widget.Scroller;
import android.widget.TextView;

public class ScrollTextView extends TextView {

// scrolling feature
private Scroller mSlr;

// milliseconds for a round of scrolling
private int mRndDuration = 250;

// the X offset when paused
private int mXPaused = 0;

// whether it's being paused
private boolean mPaused = true;

/*
* constructor
*/
public ScrollTextView(Context context) {
this(context, null);
// customize the TextView
setSingleLine();
setEllipsize(null);
setVisibility(INVISIBLE);
}

/*
* constructor
*/
public ScrollTextView(Context context, AttributeSet attrs) {
this(context, attrs, android.R.attr.textViewStyle);
// customize the TextView
setSingleLine();
setEllipsize(null);
setVisibility(INVISIBLE);
}

/*
* constructor
*/
public ScrollTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// customize the TextView
setSingleLine();
setEllipsize(null);
setVisibility(INVISIBLE);
}

/**
* begin to scroll the text from the original position
*/
public void startScroll() {
// begin from the very right side
mXPaused = -1 * getWidth();
// assume it's paused
mPaused = true;
resumeScroll();
}

/**
* resume the scroll from the pausing point
*/
public void resumeScroll() {

if (!mPaused)
return;

// Do not know why it would not scroll sometimes
// if setHorizontallyScrolling is called in constructor.
setHorizontallyScrolling(true);

// use LinearInterpolator for steady scrolling
mSlr = new Scroller(this.getContext(), new LinearInterpolator());
setScroller(mSlr);

int scrollingLen = calculateScrollingLen();
int distance = scrollingLen - (getWidth() + mXPaused);
int duration = (new Double(mRndDuration * distance * 1.00000
/ scrollingLen)).intValue();

setVisibility(VISIBLE);
mSlr.startScroll(mXPaused, 0, distance, 0, duration);
mPaused = false;
}

/**
* calculate the scrolling length of the text in pixel
*
* @return the scrolling length in pixels
*/
private int calculateScrollingLen() {
TextPaint tp = getPaint();
Rect rect = new Rect();
String strTxt = getText().toString();
tp.getTextBounds(strTxt, 0, strTxt.length(), rect);
int scrollingLen = rect.width() + getWidth();
rect = null;
return scrollingLen;
}

/**
* pause scrolling the text
*/
public void pauseScroll() {
if (null == mSlr)
return;

if (mPaused)
return;

mPaused = true;

// abortAnimation sets the current X to be the final X,
// and sets isFinished to be true
// so current position shall be saved
mXPaused = mSlr.getCurrX();

mSlr.abortAnimation();
}

@Override
/*
* override the computeScroll to restart scrolling when finished so as that
* the text is scrolled forever
*/
public void computeScroll() {
super.computeScroll();

if (null == mSlr) return;

if (mSlr.isFinished() && (!mPaused)) {
this.startScroll();
}
}

public int getRndDuration() {
return mRndDuration;
}

public void setRndDuration(int duration) {
this.mRndDuration = duration;
}

public boolean isPaused() {
return mPaused;
}
}
/*************************************************************************/

Issues to be fixed:
  1. Do not know why it would not scroll sometimes if setHorizontallyScrolling is called in constructor;
  2. The scrolling is not smooth enough. Maybe it's because of the single thread model of Android UI;

Tested on:
Windows XP
Android SDK 1.0 rc2
Android Emulator 1.0
Android Debug Bridge version 1.0.20