2013.11.09 22:56


안드로이드/Android LayoutInflater 사용 방법




1) LayoutInflater란?

XML에 정의된 Resource(자원) 들을 View의 형태로 반환해 줍니다. 보통 자바 코드에서 View, ViewGroup 을 사용하거나, Adpter의 getview() 또는 Dialog, Popup 구현시 배경화면이 될 Layout을 만들어 놓고 View의 형태로 반환 받아 Acitivity에서 실행 하게 됩니다.


우리가 보통 Activity를 만들면 onCreate() 메서드에 기본으로 추가되는 setContentView(R.layout.activity_main) 메서드와 같은 원리라고 생각하시면 됩니다. 이 메서드 또한 activity_main.xml 파일을 View로 만들어서 Activity 위에 보여주고 있습니다. 사용자의 화면에 보여지는 것들은 Activity 위에 있는 View라는 점을 잊지 말아 주세요~! 



2) LayoutInflater 예제 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
package arabiannight.tistory.com.layoutinflater;
 
import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.RelativeLayout;
import android.widget.RelativeLayout.LayoutParams;
import android.widget.TextView;
 
public class MainActivity extends Activity {
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
         
        // Inflater View 만들기
        View view = (View) getLayoutInflater().
                inflate(R.layout.activity_main, null);
         
        // Inflate된 View에서 Resource(ViewGroup) 얻어 오기~!
        RelativeLayout bg = (RelativeLayout) view.findViewById(R.id.rl_background);
        bg.setBackgroundColor(Color.GREEN);
         
        // Inflate된 View에서 Child인 TextView를 얻어 오기
        TextView tv = (TextView) view.findViewById(R.id.tv_content);
        tv.setGravity(Gravity.CENTER);
         
        // Child View인 TextView 속성 재정의 하기 (부모의 속성을 얻어옴)
        RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams)
                tv.getLayoutParams();
         
        params.width = LayoutParams.MATCH_PARENT;
        params.height = LayoutParams.WRAP_CONTENT;
         
        tv.setLayoutParams(params);
         
         
        /**
         * <오류코드>
         * RelativeLayout.LayoutParams bg_params = (RelativeLayout.LayoutParams)
         *      bg.getLayoutParams();
         *
         *  bg.setLayoutParams(bg_params);
         */
         
        // bg는 위의 부모가 없기 때문에 위의 속성을 사용하면 에러 발생 후 죽게 됩니다.
        // 그래도 사용해야 되는 경우가 생긴다면
        // ViewGroup.LayoutParams 을 사용해서 넣어 주시거나(부모가 없어도 LayoutParams 사용가능)
        // XML에 빈 부모를 하나 더 생성 하셔서 bg를 차일드로 넣고 작업 하시기 바랍니다.^^
        // 빈 부모의 속성(LayoutParams)를 지정해 주셔야 합니다.
         
        setContentView(view);
         
    }
 
}



아래의 자바코드와 XML은 동일한 작업 입니다.

<자바코드>

1
2
3
4
5
6
7
8
// Child View인 TextView 속성 재정의 하기 (부모의 속성을 얻어옴)
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams)
        tv.getLayoutParams();
         
params.width = LayoutParams.MATCH_PARENT;
params.height = LayoutParams.WRAP_CONTENT;
         
tv.setLayoutParams(params);


<XML 모습>



3) 주의사항 

<필독!!>

1) 위의 코드에서 bg(최상위 view) 는 위의 부모가 없기 때문에 위의 속성(getLayoutParams)을 사용하면 에러 발생 후 죽게 됩니다. 그래도 사용해야 되는 경우가 생긴다면 ViewGroup.LayoutParams 을 사용해서 넣어 주시거나 (부모가 없어도 LayoutParams 사용가능), XML에 빈 부모를 하나 더 생성 하셔서 bg를 차일드로 넣고 작업 하시기 바랍니다.^^ 차일드에 넣어 사용시 빈 부모의 속성(LayoutParams)를 지정해 주셔야 합니다.


2) LayoutInflater의 inflate() 메서드로 Layout을 inflate 한 경우에는 폴더별(Land, Port) Layout을 저절로 참조 하게 됩니다.


3) Resource ID(XML Layout의 Child View)는 inflate() 시 Casting 에러로 APP이 종료되게 됩니다. Resource ID 별로 inflate 시킬수가 없습니다. 꼭 Layout을 inflate 시켜야 View를 얻을 수 있습니다.


4) infalte 된 View의 Child 라면 findViewById는 절대 inflate된 View.findViewById 로 찾아야 합니다. 아니면 View를 참조 할 수 없습니다.


5) LayoutInflater된 View(xml)의 LayoutParems 속성은 (Width) wrap_content, (Height) wrap_content으로 변경 됩니다. 아무리 xml에 Layout_width, Layout_height 속성을 match_parent를 주어도 코드에서 infalte를 한다면 시스템은 infalte 된 View(xml)의 Layout_width,  Layout_height 속성을 wrap_content, wrap_content로 강제로 바꿔 버립니다. 왜냐하면 inflate된 View(xml)는 parent가 없어 지기 때문에 강제로 속성을 변경해 버리는 것이지요. 이점 꼭 명심하세요. ~!


6) inflate된 View에 다시 한번 LayoutInflater를 사용한다면 기존의 findviewID와 Event들이 모두 사라 집니다. View의 참조변수에 다른 객체를 넣는다고 생각 하시면 됩니다. 그렇다면 모두 초기화가 되겠죠? 이점 유의해 주세요^^




파일첨부 : 

TestLayoutinflater.zip




스크린샷 : 






신고


Posted by injunech
2013.11.09 21:57


Custom Android TabWidget with Badges

Written by  on August 16, 2011 in Dev Blog - 7 Comments

For an android app I’m working on I needed to present badges for tabs much like on the iPhone. I looked around for a bit but could not find any good solution for this. It seems the android SDK does not provide this feature out of the box. At least I could not find it. So I had a go at writing a custom TabWidget for this nifty feature.

I’m sure it can be made to look even better with some work. The icon is not the most pretty image and should probably be replaced. Called badge.png in the source files.

I used a singleton class BadgeTabManager to manage the tabs and get access to them from anywhere in the app. I guess this approach could be changed if several tabwidgets need to be used at the same time.

The badges are set by a simple call:

BadgeTabManager.getInstance().setBadgeAtIndex(5, 2);

The BadgeTabWidget looks like this:

/*
 * Copyright (C) 2011 Nilisoft
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.nilisoft.examples.badgetabs;

import java.util.HashMap;

import com.nilisoft.examples.R;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.view.View;
import android.widget.TabWidget;

public class BadgeTabWidget extends TabWidget{

 HashMap<integer badge=""> map;

 public BadgeTabWidget(Context context) {
  super(context);

  map = new HashMap<integer badge="">();

 }

 public BadgeTabWidget(Context c, AttributeSet set){
  super(c, set);

  map = new HashMap<integer badge="">();
 }

 public int getBadgeNumAtIndex(int index){
  Badge b = map.get(index);
  if (b == null){
   return 0;
  }
  else{
   return b.getNum();
  }
 }

 public void setBadgeAtIndex(int num, int index){
  Badge b = map.get(index);
  if (b == null){
   b = new Badge();
   map.put(index, b);
  }
  b.setNum(num);
public void setBadgeAtIndex(int num, int index){
  Badge b = map.get(index);
  if (b == null){
   b = new Badge();
   map.put(index, b);
  }
  b.setNum(num);

  // should probably use some other way to update the view (repaint the tabs) but this works...
  this.getChildAt(index).setVisibility(View.INVISIBLE);
  this.getChildAt(index).setVisibility(View.VISIBLE);
 }

 }

 @Override
 protected boolean drawChild (Canvas canvas, View child, long drawingTime){
  boolean b = super.drawChild(canvas, child, drawingTime);

  // figure out our index in the tabs, need it for the badge number
  int index = 0;
  for(int i=0; i < this.getTabCount(); i++){
   if (this.getChildAt(i) == child){
    index = i;
    break;
   }
  }

  int num = this.getBadgeNumAtIndex(index);

  if (num > 0){
   Bitmap src = BitmapFactory.decodeResource(this.getResources(),R.drawable.badge);
   Bitmap badge = Bitmap.createScaledBitmap(src, 24, 19, true);

   int x =  child.getRight()-badge.getWidth()-5;

   canvas.drawBitmap(badge, x, 0, new Paint());

   Typeface face = Typeface.create("Verdana", Typeface.BOLD);
   Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
   paint.setTypeface(face);
   paint.setTextSize(12);
   paint.setARGB(255, 255, 255, 255);

   String text = ""+num;
   Rect bounds = new Rect();
   paint.getTextBounds(text, 0, text.length(), bounds);

   canvas.drawText(
     text,
     (x+badge.getWidth()/2)-bounds.width()/2,
     // -1 here because the badge icon is looking as it does with some
     // more space at the bottom for shadows, might need change if the
     // size of the icon is changed
     (badge.getHeight()/2)+bounds.height()/2 -2,
     paint);

  }

  return b;
 }

 private class Badge {
  int num;

  public Badge(){
   num = 0;
  }

  public void setNum(int num){
   this.num = num;
  }

  public int getNum(){
   return num;
  }

 }

}
</integer></integer></integer>

And the full source code the for example project can be downloaded here: BadgeTabs

Enjoy! And please let me know if you find this useful in any of your apps.

The end result looks like this:

신고


Posted by injunech
2013.07.27 16:44



RemoteOne.exe


신고

'Project > Remote' 카테고리의 다른 글

MyRemote Ver 1.41  (0) 2014.06.08
MyRemote_Install ver1.4  (0) 2014.05.13
RemoteOne  (0) 2013.07.27
Remote One 참고자료  (0) 2013.07.18
원격 데스크톱의 속도와 구동 원리에 대한 간단한 정보  (0) 2013.07.16
MyRemote_Install ver1.3  (0) 2013.02.22


Posted by injunech

티스토리 툴바