// DPI値を取得する
TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 6, this.getResources().getDisplayMetrics())
2012年6月13日水曜日
2012年6月11日月曜日
AndroidでSilverlightのWrapPanel風のViewGroupが欲しい その2
前回作ったコントロールでは、動的にadd もしくは remove した時に正常に動作しませんでした。
今回は ViewGroup を直接継承し実装してみました。
子要素の配置を行うためいに ViewGroup#onLayout をオーバーライドします。
ここで View#getWidth の戻り値は 0 となってしまうため、 View#getMeasuredWidthを使用します。
ですが、素の状態では View#getMeasuredWidth の戻り値も 0 となり、コントロールのサイズを取得できません。
そこでまず ViewGroup#onMeasure をオーバーライドし子要素に対してView#measureを呼び出します。
子要素の配置を行うためいに ViewGroup#onLayout をオーバーライドします。
ここで View#getWidth の戻り値は 0 となってしまうため、 View#getMeasuredWidthを使用します。
ですが、素の状態では View#getMeasuredWidth の戻り値も 0 となり、コントロールのサイズを取得できません。
そこでまず ViewGroup#onMeasure をオーバーライドし子要素に対してView#measureを呼び出します。
以下の呪文を記述
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int width = View.resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
final int height = View.resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
this.setMeasuredDimension(width, height);
int childWidthSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.UNSPECIFIED);
int childHeightSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.UNSPECIFIED);
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
getChildAt(i).measure(childWidthSpec, childHeightSpec);
}
}
これを書けば、View#getMeasuredWidthで値が取得できるようになります。
ちゃんと理解してはいない。
ちゃんと理解してはいない。
あとは前回 View#onWindowFocusChangedのなかに書いてた事をView#onLayoutに記述してやればOK。
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int count = this.getChildCount();
// 行の高さ
int rowHeight = 0;
// 現在の行の幅
int currentRowWidth = 0;
int rowMaxWidth = this.getWidth();
int top = 0;
for (int i = 0; i < count; i++) {
View child = this.getChildAt(i);
if (child.getVisibility() != View.GONE) {
int childWidth = child.getMeasuredWidth();
int childHeight = child.getMeasuredHeight();
if (rowMaxWidth < currentRowWidth + childWidth) {
// はみ出すので演算をやり直す。
// 次行の位置を設定
top += rowHeight < childHeight ? childHeight : rowHeight;
// 現在行の高さを初期化
rowHeight = 0;
// 現在行の幅を初期化
currentRowWidth = 0;
}
// コントロールを適切な位置に配置
child.layout(
currentRowWidth,
top,
currentRowWidth + childWidth,
top + childHeight);
// 行の高さを更新する必要があるか
rowHeight =
rowHeight < childHeight ? childHeight : rowHeight;
// 現在のコントロール幅を合計値に加算する
currentRowWidth += childWidth;
}
}
}
良い感じ良い感じ。
実際にはMarginなんかが設定されるハズ。
なの以下の クラス をInner Classとして作成。
なの以下の クラス をInner Classとして作成。
public static class LayoutParams extends MarginLayoutParams {
public LayoutParams(Context context, AttributeSet attr) { super(context, attr); }
public LayoutParams(int width, int height) { super(width, height); }
public LayoutParams(ViewGroup.LayoutParams source) { super(source); }
public LayoutParams(MarginLayoutParams source) { super(source); }
}
MarginLayoutParams を継承しただけ。今後を考えてInner Classとした。
このクラスを定義しただけで、(WrapLayout.LayoutParams)child.getLayoutParams() なんてした日には楽しい結末(ClassCastException)が待っているので、 以下の Method を Override
このクラスを定義しただけで、(WrapLayout.LayoutParams)child.getLayoutParams() なんてした日には楽しい結末(ClassCastException)が待っているので、 以下の Method を Override
・ ViewGroup#generateLayoutParams
・ ViewGroup#generateDefaultLayoutParams
・ ViewGroup#checkLayoutParams
・ ViewGroup#generateLayoutParams
・ ViewGroup#generateDefaultLayoutParams
・ ViewGroup#checkLayoutParams
・ ViewGroup#generateLayoutParams
@Override
public WrapLayout.LayoutParams generateLayoutParams(AttributeSet attrs) {
return new WrapLayout.LayoutParams(getContext(), attrs);
}
@Override
protected WrapLayout.LayoutParams generateDefaultLayoutParams() {
return new WrapLayout.LayoutParams(WrapLayout.LayoutParams.WRAP_CONTENT, WrapLayout.LayoutParams.WRAP_CONTENT);
}
@Override
protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
return p instanceof WrapLayout.LayoutParams;
}
@Override
protected WrapLayout.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
return new WrapLayout.LayoutParams(p);
}
設定された margin を使って配置を行うように ViewGroup#onLayout に修正を加える。
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int count = this.getChildCount();
// 行の高さ
int rowHeight = 0;
// 現在の行の幅
int currentRowWidth = 0;
int rowMaxWidth = this.getWidth();
int top = 0;
for (int i = 0; i < count; i++) {
View child = this.getChildAt(i);
if (child.getVisibility() != View.GONE) {
WrapLayout.LayoutParams lp =
(WrapLayout.LayoutParams)child.getLayoutParams();
int childWidth = child.getMeasuredWidth();
int childHeight = child.getMeasuredHeight();
int childTotaWidth = childWidth + lp.rightMargin + lp.leftMargin;
int childTotalHeight = childHeight + lp.topMargin + lp.bottomMargin;
if (rowMaxWidth < currentRowWidth + childTotaWidth) {
// はみ出すので演算をやり直す。
// 高さを設定
top += rowHeight < childTotalHeight ? childTotalHeight : rowHeight;
// 現在行の高さを初期化
rowHeight = 0;
// 現在行の幅を初期化
currentRowWidth = 0;
}
child.layout(
currentRowWidth + lp.leftMargin,
top + lp.topMargin,
currentRowWidth + childWidth + lp.rightMargin,
top + childHeight + lp.bottomMargin);
rowHeight =
rowHeight < childTotalHeight ? childTotalHeight : rowHeight;
currentRowWidth += childTotaWidth;
}
}
}
これでMarginが有効になったWrapLayoutの出来上がり。
ソースコード全文(import等は割愛)
ソースコード全文(import等は割愛)
public class WrapLayout extends ViewGroup {
//==================================================================
// constructor
//==================================================================
public WrapLayout(Context context) { super(context); }
public WrapLayout(Context context, AttributeSet attrs) { super(context, attrs); }
public WrapLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); }
//==================================================================
// public methods
//==================================================================
@Override
public WrapLayout.LayoutParams generateLayoutParams(AttributeSet attrs) {
return new WrapLayout.LayoutParams(getContext(), attrs);
}
//==================================================================
// protected methods
//==================================================================
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int width = View.resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
final int height = View.resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
this.setMeasuredDimension(width, height);
int childWidthSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.UNSPECIFIED);
int childHeightSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.UNSPECIFIED);
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
getChildAt(i).measure(childWidthSpec, childHeightSpec);
}
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int count = this.getChildCount();
// 行の高さ
int rowHeight = 0;
// 現在の行の幅
int currentRowWidth = 0;
int rowMaxWidth = this.getWidth();
int top = 0;
for (int i = 0; i < count; i++) {
View child = this.getChildAt(i);
if (child.getVisibility() != View.GONE) {
WrapLayout.LayoutParams lp =
(WrapLayout.LayoutParams)child.getLayoutParams();
int childWidth = child.getMeasuredWidth();
int childHeight = child.getMeasuredHeight();
int childTotaWidth = childWidth + lp.rightMargin + lp.leftMargin;
int childTotalHeight = childHeight + lp.topMargin + lp.bottomMargin;
if (rowMaxWidth < currentRowWidth + childTotaWidth) {
// はみ出すので演算をやり直す。
// 高さを設定
top += rowHeight < childTotalHeight ? childTotalHeight : rowHeight;
// 現在行の高さを初期化
rowHeight = 0;
// 現在行の幅を初期化
currentRowWidth = 0;
}
child.layout(
currentRowWidth + lp.leftMargin,
top + lp.topMargin,
currentRowWidth + childWidth + lp.rightMargin,
top + childHeight + lp.bottomMargin);
rowHeight =
rowHeight < childTotalHeight ? childTotalHeight : rowHeight;
currentRowWidth += childTotaWidth;
}
}
}
@Override
protected WrapLayout.LayoutParams generateDefaultLayoutParams() {
return new WrapLayout.LayoutParams(WrapLayout.LayoutParams.WRAP_CONTENT, WrapLayout.LayoutParams.WRAP_CONTENT);
}
@Override
protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
return p instanceof WrapLayout.LayoutParams;
}
@Override
protected WrapLayout.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
return new WrapLayout.LayoutParams(p);
}
//==================================================================
// inner class
//==================================================================
public static class LayoutParams extends MarginLayoutParams {
public LayoutParams(Context context, AttributeSet attr) { super(context, attr); }
public LayoutParams(int width, int height) { super(width, height); }
public LayoutParams(ViewGroup.LayoutParams source) { super(source); }
public LayoutParams(MarginLayoutParams source) { super(source); }
}
}
2012年6月6日水曜日
AndroidでSilverlightのWrapPanel風のViewGroupが欲しい
AndroidでSilverlightのWrapPanelのように自動で折り返すViewGroupが欲しいです。
デフォルトじゃないみたいなので、いろいろ漁ってると以下の記事を発見。
・Androidでボタンを横に並べて自動で折り返す
ほほー。RelativeLayoutでござるか。
使 っ た こ と な い ん で す よ ね 。
上記の記事を使いまわしが効くようにコントロール化してみました。
かなり適当。
わかってます。onWindowFocusChangedにaddViewしたらダメじゃね?ってのはわかってます。
とりあえずです。
[[Activity]]
良い感じ。
デフォルトじゃないみたいなので、いろいろ漁ってると以下の記事を発見。
・Androidでボタンを横に並べて自動で折り返す
ほほー。RelativeLayoutでござるか。
使 っ た こ と な い ん で す よ ね 。
上記の記事を使いまわしが効くようにコントロール化してみました。
かなり適当。
public class WrapLayout extends RelativeLayout {
public WrapLayout(Context context) {
super(context);
}
public WrapLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public WrapLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
public void addView(View child) {
// idが未設定の場合は乱数でどうにかする。
if (child.getId() == -1) { child.setId(new Random(System.currentTimeMillis()).nextInt(Integer.MAX_VALUE)); }
super.addView(child);
}
@Override
public void addView(View child, int width, int height) {
// idが未設定の場合は乱数でどうにかする。
if (child.getId() == -1) { child.setId(new Random(System.currentTimeMillis()).nextInt(Integer.MAX_VALUE)); }
super.addView(child, width, height);
}
@Override
public void addView(View child, ViewGroup.LayoutParams params) {
// idが未設定の場合は乱数でどうにかする。
if (child.getId() == -1) { child.setId(new Random(System.currentTimeMillis()).nextInt(Integer.MAX_VALUE)); }
super.addView(child, params);
}
@Override
public void addView(View child, int index) {
// idが未設定の場合は乱数でどうにかする。
if (child.getId() == -1) { child.setId(new Random(System.currentTimeMillis()).nextInt(Integer.MAX_VALUE)); }
super.addView(child, index);
}
@Override
public void addView(View child, int index, ViewGroup.LayoutParams params) {
// idが未設定の場合は乱数でどうにかする。
if (child.getId() == -1) { child.setId(new Random(System.currentTimeMillis()).nextInt(Integer.MAX_VALUE)); }
super.addView(child, index, params);
}
@Override
public void onWindowFocusChanged(boolean hasWindowFocus) {
super.onWindowFocusChanged(hasWindowFocus);
// 子供の数を取得
int l = this.getChildCount();
// 無いなら何もしない
if (l == 0) {
return;
}
// ディスプレイの横幅を取得
WindowManager wm = (WindowManager) this.getContext().getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
// 1行最大長
int max = display.getWidth();
// 一番最初は基点となるので何もしない
View pline = this.getChildAt(0);
// 現在の1行の長さ
int currentTotal = pline.getWidth();
for (int i = 1; i < l; i++) {
int w = this.getChildAt(i).getWidth();
RelativeLayout.LayoutParams layoutParams =
(RelativeLayout.LayoutParams) this.getChildAt(i).getLayoutParams();
// 横幅を超えないなら前のボタンの右に出す
if (max > currentTotal + w) {
// 現在長に処理対象コントロール長を加算
currentTotal += w;
layoutParams.addRule(RelativeLayout.ALIGN_TOP, this.getChildAt(i - 1).getId());
layoutParams.addRule(RelativeLayout.RIGHT_OF, this.getChildAt(i - 1).getId());
} else {
// 横最大長を超過した場合は折り返す
layoutParams.addRule(RelativeLayout.BELOW, pline.getId());
// 基点を変更
pline = this.getChildAt(i);
// 長さをリセット
currentTotal = pline.getWidth();
}
}
}
}
わかってます。onWindowFocusChangedにaddViewしたらダメじゃね?ってのはわかってます。
とりあえずです。
[[Activity]]
public class MainActivity extends Activity {
/** Called when the activity is first created. */
String[] strings = { "てst1", "てst2", "てst3", "てst4", "てst5", "てst6", "てst7", "てst8", "てst9", "てst10", "てst111111a", "てst111", "てst234"};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
WrapLayout layout = (WrapLayout)this.findViewById(R.id.FixedGridLayout);
for (String string : strings) {
Button btn = new Button(this);
btn.setText(string);
//btn.setId(random.nextInt(Integer.MAX_VALUE));
layout.addView(btn);
}
}
}
[[出力結果]]良い感じ。
2012年6月5日火曜日
[Silverlight] UIスレッド上で処理を実行する。
System.Windows.Deployment.Current.Dispatcher.BeginInvoke(() =>{ .... });
Triggerでシーケンス値を自動採番
以下のようなテーブルが存在したとする。
テーブル名 : [MST_Magazine]
フィールド
| 項目名 | 型 | 備考 |
|---|---|---|
| ID | 数値 | PK 連番でデータを格納 |
| Publisher_ID | 数値 | |
| Name | 文字列 |
このようなテーブルではIDはシーケンスでの採番となる。
しかし、OracleではSQLServerのように、型として自動採番の型が存在しない。
そこで、トリガを用いて自動採番を行う。
CREATE OR REPLACE TRIGGER TRG_MST_Magazine_ID
BEFORE Insert
ON MST_Magazine
FOR EACH ROW
BEGIN
IF :NEW.ID IS NULL THEN
SELECT SEQ_Magazine_ID.NEXTVAL INTO :NEW.ID FROM DUAL;
END IF;
END;
上記のトリガは、MST_MagazineテーブルへのInsert時に起動し、
InsertされたMST_Magazine.ID項目がNULLの場合、SEQ_Magazine_ID.Nextvalの値を使用する。
これにより、IDを指定せずMST_MagazineテーブルへのInsertを行った場合は自動で数値が採番される。
HtmlPage.Window.Navigate で cookie を使用する。
Silverlightなんかで、画面を切り替えるときに HtmlPage.Window.Navigate で遷移させたりしますけども、
その時にCookieを使用したいと思いました。
System.Net.Cookieとかあるからこれを使うのかと思ったけども、どうやら違う。
こいつはHttpWebRequestの時に使うみたい。
それじゃあ、こまります。
ええ、困りますとも。
だって画面遷移をさせたいんだから。
さてどうするかと言うと、System.Windows.Browser.HtmlPageのDocumentプロパティのSetPropertyで設定してあげればいいんでがす。
[[サンプル]]
HtmlPage.Document.SetProperty( "cookie", "Key1=Value1" ); HtmlPage.Document.SetProperty( "cookie", "Key2=Value2" ); HtmlPage.Window.Navigate ( new Uri( "http://....", UriKind.RelativeOrAbsolute), "_self" );
で、Cookie情報を取得するには HtmlPage.Document.Cookies プロパティに格納される。
これは文字列でドバーっと入ってるので、いいように加工して使うしか無いんでしょうか。
めんどくさい。
登録:
投稿 (Atom)
