Android Seed Project 만들기 3
in Android
Android Seed Project 만들기 3
1편에서는 기본 메인 액티비티에 NavigationTabBar을 추가하고 Iconic을 이용해 아이콘도 추가하였다.
2편에서는 앱의 타이틀바(혹은 액션바) 커스텀과 Fragment를 이용해 페이지를 만들어 보았다.
3편에서는 Kotlin으로 코드를 수정하여 보았다. Android Studio 3.0부터는 자동변환 기능이 있지만 그저 단순변환이므로 코틀린을 학습하면서 조금씩 코드 구조도 다듬었다.
기존의 프로젝트에서 브랜치만 분리하여 kotlin으로 작성하였다.
master branch = 자바
kotlin branch = 코틀린
코틀린 개발 방법
코틀린 사용
- build.gradle(Module:app) 파일의 최상단 kotlin-android plugin 추가
- build.gradle(Project:Android-seed-project)에 kotlin_version, classpath 추가
- dependencies에 kotlin-stdlib 추가
kotlin android extensions 사용
import kotlinx.android.synthetic.activity_main.*
을 추가- activity_main.xml의 View id들을 변수처럼 사용
build.gradle(Application:Android-seed-project)
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
ext.kotlin_version = '1.2.30' # 추가
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.1.3'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" # 추가
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
google()
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
Build.gradle(Module:app)
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android' #추가
apply plugin: 'kotlin-android-extensions' #추가
dependencies {
...
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" #추가
implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version" #추가
}
언어별 코드 비교
MainActivity.java
public class MainActivity extends AppCompatActivity {
@BindView(R.id.ntb_horizontal)
NavigationTabBar navTab;
private ViewPager viewPager;
private MainTabPagerAdapter viewPagerAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate (savedInstanceState);
setContentView (R.layout.activity_main);
ButterKnife.bind (this);
initUI ();
}
private void initUI() {
viewPager = findViewById (R.id.vp_horizontal_ntb);
viewPagerAdapter = new MainTabPagerAdapter (getSupportFragmentManager ());
initPages ();
viewPager.setAdapter (viewPagerAdapter);
initNavigationBar ();
}
private void initPages() {
viewPagerAdapter.addFragment (SampleFragment.newInstance ());
viewPagerAdapter.addFragment (new Fragment ());
}
private void initNavigationBar() {
int activeColor = getResources ().getColor (R.color.tab_active);
int inactiveColor = getResources ().getColor (R.color.tab_inactive);
navTab.setBgColor (Color.WHITE);
navTab.setActiveColor (activeColor);
navTab.setInactiveColor (inactiveColor);
navTab.setIsTitled (true);
final ArrayList<NavigationTabBar.Model> models = new ArrayList<> ();
Drawable iList = new IconicsDrawable (this, Ionicons.Icon.ion_ios_folder_outline).sizeDp (24);
Drawable iCog = new IconicsDrawable (this).icon (FontAwesome.Icon.faw_cog).sizeDp (24);
String modelBgColor = "#ffffff";
models.add (
new NavigationTabBar.Model.Builder (
iList,
Color.parseColor (modelBgColor))
.title (getString (R.string.main_nav_first))
.build ()
);
models.add (
new NavigationTabBar.Model.Builder (
iCog,
Color.parseColor (modelBgColor))
.title (getString (R.string.main_nav_second))
.build ()
);
navTab.setModels (models);
navTab.setViewPager (viewPager, 0);
navTab.setBehaviorEnabled (true);
navTab.setBadgeSize (20);
navTab.bringToFront ();
}
}
MainActivity.kt
class MainActivity : AppCompatActivity() {
private lateinit var viewPagerAdapter: MainTabPagerAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
initUI()
}
private fun initUI() {
initPages()
initNavigationBar()
}
private fun initPages() {
viewPagerAdapter = MainTabPagerAdapter(supportFragmentManager)
viewPagerAdapter.addFragment(SampleFragment().newInstance())
viewPagerAdapter.addFragment(Fragment())
viewPager.adapter = viewPagerAdapter
}
private fun initNavigationBar() {
val activeColor = resources.getColor(R.color.tab_active)
val inactiveColor = resources.getColor(R.color.tab_inactive)
navTab.bgColor = Color.WHITE
navTab.activeColor = activeColor
navTab.inactiveColor = inactiveColor
navTab.setIsTitled(true)
navTab.models = initNavTabs()
navTab.setViewPager(viewPager)
navTab.isBehaviorEnabled = true
navTab.badgeSize = 20f
navTab.bringToFront()
}
private fun initNavTabs(): ArrayList<NavigationTabBar.Model> {
val tabs: ArrayList<NavigationTabBar.Model> = ArrayList()
val listIcon: Drawable = IconicsDrawable(this, Ionicons.Icon.ion_ios_folder_outline).sizeDp(24)
val settingIcon: Drawable = IconicsDrawable(this).icon(FontAwesome.Icon.faw_cog).sizeDp(24)
val listTitle = getString(R.string.main_nav_first)
val cogTitle = getString(R.string.main_nav_second)
val listTab = Builder(listIcon, Color.WHITE).title(listTitle).build()
val settingTab = Builder(settingIcon, Color.WHITE).title(cogTitle).build()
tabs.add(listTab)
tabs.add(settingTab)
return tabs
}
}
MainTabPagerAdapter.java
public class MainTabPagerAdapter extends FragmentStatePagerAdapter {
private List<Fragment> fragmentList = new ArrayList<> ();
public MainTabPagerAdapter(FragmentManager fragmentManager) {
super (fragmentManager);
}
@Override
public int getCount() {
return fragmentList.size ();
}
@Override
public Fragment getItem(int position) {
return fragmentList.get (position);
}
public void setFragmentList(List<Fragment> fragmentList) {
this.fragmentList = fragmentList;
notifyDataSetChanged ();
}
public void addFragment(Fragment fragment) {
fragmentList.add (fragment);
notifyDataSetChanged ();
}
}
MainTabPagerAdapter.kt
class MainTabPagerAdapter(fragmentManager: FragmentManager) : FragmentStatePagerAdapter(fragmentManager) {
private var fragmentList: MutableList<Fragment> = ArrayList()
override fun getCount(): Int {
return fragmentList.size
}
override fun getItem(position: Int): Fragment {
return fragmentList[position]
}
fun setFragmentList(fragmentList: MutableList<Fragment>) {
this.fragmentList = fragmentList
notifyDataSetChanged()
}
fun addFragment(fragment: Fragment) {
fragmentList.add(fragment)
notifyDataSetChanged()
}
}
SampleFragment.java
public class SampleFragment extends Fragment {
public SampleFragment() { }
public static SampleFragment newInstance() {
return new SampleFragment ();
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate (R.layout.fragment_sample, container, false);
initToolbar (view);
return view;
}
private void initToolbar(View view) {
if(Build.VERSION.SDK_INT >= 21) {
// 21 버전 이상일 때
getActivity ().getWindow ().setStatusBarColor (Color.BLACK);
}
Toolbar toolbar = view.findViewById (R.id.toolbar);
toolbar.setTitle ("");
((AppCompatActivity) getActivity ()).setSupportActionBar (toolbar);
TextView title = toolbar.findViewById (R.id.title);
title.setText ("main");
}
}
SampleFragment.kt
class SampleFragment : Fragment() {
fun newInstance(): SampleFragment {
return SampleFragment()
}
override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val view = inflater!!.inflate(R.layout.fragment_sample, container, false)
if (Build.VERSION.SDK_INT >= 21)
activity.window.statusBarColor = Color.BLACK
view.toolbar.title.text = "hi"
activity.setActionBar(toolbar as Toolbar?)
return view
}
}
코틀린 사용 후기
단순하게 기존에 만든 프로젝트를 코틀린으로 변경하는 작업이라 크게 사용한 기술은 없었지만
사용하면서 되게 코딩이 편하다는 느낌을 받을 수 있었다. 기술보다는 IDE가 사기 같다. 갓텔리제이 만세
가장 좋았던 장점은 getActivity(), findViewById() 등의 함수없이도 바인딩이 된다는 점이 좋았다.
Kotlin Android Extensions 이라고 부르며 xml에 있는 View들의 id를 변수로 사용할 수 있는 점이 좋았다.