[Android Studio|Kotlin] View
ownership903
Posted on February 27, 2022
basic Setting
buildFeatures {
viewBinding = true
}
1) custom View
[MainActivity.kt]
class MainActivity : AppCompatActivity() {
val binding by lazy {ActivityMainBinding.inflate(layoutInflater)}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(binding.root)
val customView = CustomView(this)
binding.frameLayout.addView(customView)
}
}
[CustomView.kt]
class CustomView(context: Context) : View(context) {
override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
val paint = Paint()
paint.color = Color.BLACK
paint.textSize = 100f
canvas?.run {
drawText("Hello", 0f, 100f, paint)
customDrawCircle(canvas)
customDrawRect(canvas)
}
}
fun customDrawCircle(canvas:Canvas) {
val paint = Paint()
paint.style = Paint.Style.FILL
paint.color = Color.BLUE
canvas.drawCircle(150f, 300f, 100f, paint)
}
fun customDrawRect(canvas: Canvas) {
val paint = Paint()
paint.style = Paint.Style.STROKE
paint.strokeWidth = 20f
paint.color = Color.GREEN
val rect = RectF(50f, 450f, 250f, 650f)
canvas.drawRect(rect, paint)
}
}
[activity_main.xml]
<androidx.constraintlayout.widget.ConstraintLayout
<TextView />
<FrameLayout />
</androidx.constraintlayout.widget.ConstraintLayout
2) custom Widget
[MainActivity.kt]
class MainActivity : AppCompatActivity() {
val binding by lazy {ActivityMainBinding.inflate(layoutInflater)}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(binding.root)
}
}
[CustomText.kt]
class CustomText : AppCompatTextView {
constructor(context: Context) : super(context) { }
constructor(context: Context, attrs:AttributeSet) : super(context, attrs) {
val attrList = context.obtainStyledAttributes(attrs, R.styleable.CustomText)
for(i in 0 until attrList.indexCount) {
val attr = attrList.getIndex(i)
when(attr) {
R.styleable.CustomText_delimeter -> {
attrList.getString(attr)?.let {
process(it)
}
}
}
}
}
constructor(context: Context, attrs:AttributeSet, defStyleAttr:Int) : super(context, attrs, defStyleAttr ) {}
fun process(delimeter: String) {
if(text.length == 8) {
val first4 = text.substring(0,4)
val mid2 = text. substring(4,6)
val last2 = text.substring(6)
text = "$first4$delimeter$mid2$delimeter$last2"
}
}
}
[res > values > attrs.xml]
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="CustomText">
<attr name="delimeter" format="string"/>
</declare-styleable>
</resources>
[activity_mains.xml]
<androidx.constraintlayout.widget.ConstraintLayout
<com.example.myapplication.CustomText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="20220226"
app:delimeter="-"/>
</androidx.constraintlayout.widget.ConstraintLayout
3-1) ViewPager & TabLayout
[MainActivity.kt]
class MainActivity : AppCompatActivity() {
val binding by lazy {ActivityMainBinding.inflate(layoutInflater)}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(binding.root)
val list = listOf(FragmentA(), FragmentB(), FragmentC(), FragmentD() )
// create adapter
val pagerAdapter = FragmentPagerAdapter(list, this)
// connect adapter and viewpager
binding.viewPager.adapter = pagerAdapter
// Create a list of titles as many as the number of tab menus
val titles = listOf("A", "B", "C", "D")
// connect TabLayout ViewPager2
TabLayoutMediator(binding.tabLayout, binding.viewPager) { tab, position ->
tab.text = titles.get(position)
}.attach()
}
}
class FragmentPagerAdapter(val fragmentList:List<Fragment>, fragmentActivity: FragmentActivity)
: FragmentStateAdapter(fragmentActivity) {
override fun getItemCount() = fragmentList.size
override fun createFragment(position: Int) = fragmentList.get(position)
}
create [FragmentA.kt], [FragmentB.kt], [FragmentC.kt], [FragmentD.kt]
create with ([fragment_a.xml], [fragment_b.xml], [fragment_c.xml], [fragment_d.xml],)
[activity_main.kt]
<androidx.constraintlayout.widget.ConstraintLayout
<androidx.viewpager2.widget.ViewPager2 android:id="@+id/viewPager"
<com.google.android.material.tabs.TabLayout android:id="@+id/tabLayout"
<androidx.constraintlayout.widget.ConstraintLayout
4) tablayout, viewpager and recyclerview
[MainActivity.kt]
class MainActivity : AppCompatActivity() {
val binding by lazy {ActivityMainBinding.inflate(layoutInflater)}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(binding.root)
val list = listOf("MON", "TUE", "WED","THR", "FRI","SAT","SUN")
// create adapter
val pagerAdapter = CustomPagerAdapter(list)
// connect adapter and viewpager
binding.viewPager.adapter = pagerAdapter
//Create a list of tab titles - skip
// connect tablayout and viewpager
TabLayoutMediator(binding.tabLayout, binding.viewPager) { tab, position ->
tab.text = list.get(position)
}.attach()
}
}
class CustomPagerAdapter(val textList:List<String>) : RecyclerView.Adapter<CustomPagerAdapter.Holder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder {
val binding = ItemViewpagerBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return Holder(binding)
}
override fun getItemCount() = textList.size
override fun onBindViewHolder(holder: Holder, position: Int) {
holder.setItem(textList.get(position))
}
class Holder(val binding:ItemViewpagerBinding) : RecyclerView.ViewHolder(binding.root) {
fun setItem(text:String) {
binding.textView.text = text
}
}
}
[activity_main.xml]
<androidx.constraintlayout.widget.ConstraintLayout
<com.google.android.material.tabs.TabLayout android:id="@+id/tabLayout"
</com.google.android.material.tabs.TabLayout
<androidx.viewpager2.widget.ViewPager2 android:id="@+id/viewPager"
/>
</androidx.constraintlayout.widget.ConstraintLayout
[item_viewpager.xml]
<androidx.constraintlayout.widget.ConstraintLayout
<TextView android:id="@+id/textView"
</androidx.constraintlayout.widget.ConstraintLayout
5) tablayout, viewpager and recyclerview
[MainActivity.kt]
class MainActivity : AppCompatActivity() {
val binding by lazy {ActivityMainBinding.inflate(layoutInflater)}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(binding.root)
val list = loadData()
// create adapter
val pagerAdapter = CustomPagerAdapter(list)
// connect adapter and viewpager
binding.viewPager.adapter = pagerAdapter
//Create a list of tab titles
val titles = listOf("MON", "TUE", "WED","THR", "FRI","SAT","SUN")
// connect tablayout and viewpager
TabLayoutMediator(binding.tabLayout, binding.viewPager) { tab, position ->
tab.text = titles.get(position)
}.attach()
}
fun loadData() : List<Page> {
val pageList = mutableListOf<Page>()
pageList.add(Page(1, "Cloudy"))
pageList.add(Page(2, "Clear"))
pageList.add(Page(3, "Cloud"))
pageList.add(Page(4, "Rain"))
pageList.add(Page(5, "Snow"))
pageList.add(Page(6, "Typhoon"))
pageList.add(Page(7, "Fog"))
return pageList
}
}
class CustomPagerAdapter(val pageList:List<Page>) : RecyclerView.Adapter<CustomPagerAdapter.Holder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder {
val binding = ItemViewpagerBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return Holder(binding)
}
override fun getItemCount() = pageList.size
override fun onBindViewHolder(holder: Holder, position: Int) {
holder.setItem(pageList.get(position))
}
class Holder(val binding:ItemViewpagerBinding) : RecyclerView.ViewHolder(binding.root) {
fun setItem(page:Page) {
with(binding) {
textDay.text = "${page.day} DAY"
textWeather.text = page.weather
}
}
}
}
data class Page(val day:Int, val weather:String)
[activity_main.xml]
<androidx.constraintlayout.widget.ConstraintLayout
<com.google.android.material.tabs.TabLayout android:id="@+id/tabLayout"
<androidx.viewpager2.widget.ViewPager2 android:id="@+id/viewPager"
</androidx.constraintlayout.widget.ConstraintLayout
[item_viewpager.xml]
<androidx.constraintlayout.widget.ConstraintLayout
<TextView android:id="@+id/textDay"
<TextView android:id="@+id/textWeather"
</androidx.constraintlayout.widget.ConstraintLayout
6) add tablayout,viewpager, recyclerView and retrofit
[app > manifests > AndroidManifest.xml ]
<uses-permission android:name="android.permission.INTERNET"/>
[Gradle Scripts > build.gradle]
dependencies {
// fragment
implementation "androidx.fragment:fragment-ktx:1.4.1"
// retrofit
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
}
[MainActivity.kt]
class MainActivity : AppCompatActivity() {
val binding by lazy { ActivityMainBinding.inflate(layoutInflater)}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(binding.root)
// 1. load page data
val list = listOf( FragmentA(), FragmentB(), FragmentC() )
// 2. create adapter
val pagerAdapter = FragmentPagerAdapter(list, this)
// 3. connect adapter and viewpager
binding.viewPager.adapter = pagerAdapter
// Create a list of titles as many as the number of tab menus
val titles = listOf("tabname1", "tabname2", "tabname3" )
// connect TabLayout ViewPager2
TabLayoutMediator(binding.tabLayout, binding.viewPager) { tab, position ->
tab.text = titles.get(position)
}.attach()
}
}
class FragmentPagerAdapter(val fragmentList:List<Fragment>, fragmentActivity: FragmentActivity)
: FragmentStateAdapter(fragmentActivity) {
override fun getItemCount() = fragmentList.size
override fun createFragment(position: Int) = fragmentList.get(position)
}
[ApiService.kt]
interface ApiService {
@GET("/apptech")
fun getPosts(): Call<MutableList<Apptech>>
}
[ServiceGenerator.kt]
object ServiceGenerator {
private val client = OkHttpClient.Builder().build()
private val retrofit = Retrofit.Builder()
.baseUrl("https://****.herokuapp.com")
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build()
fun <T> buildService(service: Class<T>): T {
return retrofit.create(service)
}
}
[Apptech.kt]
data class Apptech(
val apptech_brand: String? = null,
val apptech_title: String? = null,
val apptech_period: String? = null,
val apptech_point: Int? = null,
val apptech_time: String? = null,
val apptech_url: String? = null
)
[ApptechAdapter.kt]
class ApptechAdapter(val apptechData: MutableList<Apptech>) : RecyclerView.Adapter<ApptechAdapter.Holder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder {
val binding = FragmentBItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return Holder(binding)
}
override fun getItemCount() = apptechData.size
override fun onBindViewHolder(holder: Holder, position: Int) {
//val apptech = apptechData.get(position)
//holder.setApptech(apptech)
return holder.setApptech(apptechData[position])
}
class Holder(val binding: FragmentBItemBinding) : RecyclerView.ViewHolder(binding.root) {
fun setApptech(apptech: Apptech) {
with(binding) {
tvTitle.text = "${apptech.apptech_brand}"
tvBody.text = "${apptech.apptech_title}"
tvTime.text = "${apptech.apptech_time}"
binding.root.setOnClickListener {
var url = "${apptech.apptech_url}"
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
ContextCompat.startActivity(itemView.context, intent, null)
}
}
}
}
}
[FragmentA.kt]
class FragmentA : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_a, container, false)
}
}
[FragmentB.kt]
class FragmentB : Fragment() {
lateinit var binding: FragmentBBinding
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = FragmentBBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val serviceGenerator = ServiceGenerator.buildService(ApiService::class.java)
val call = serviceGenerator.getPosts()
call.enqueue(object : Callback<MutableList<Apptech>> {
override fun onResponse(call: Call<MutableList<Apptech>>, response: Response<MutableList<Apptech>>) {
with(binding){
recyclerView.apply{
adapter = ApptechAdapter(response.body()!!)
layoutManager = LinearLayoutManager(activity)
}
}
}
override fun onFailure(call: Call<MutableList<Apptech>>, t: Throwable) {
t.printStackTrace()
Log.e("error", t.message.toString())
}
})
}
}
[FragmentC.kt]
class FragmentC : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_c, container, false)
}
}
[activity_main.xml]
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.google.android.material.tabs.TabLayout
android:id="@+id/tabLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<com.google.android.material.tabs.TabItem
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Monday" />
<com.google.android.material.tabs.TabItem
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Tuesday" />
<com.google.android.material.tabs.TabItem
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Wednesday" />
</com.google.android.material.tabs.TabLayout>
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/viewPager"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tabLayout" />
</androidx.constraintlayout.widget.ConstraintLayout>
[fragment_a.xml]
<androidx.constraintlayout.widget.ConstraintLayout
<\androidx.constraintlayout.widget.ConstraintLayout
[fragment_b.xml]
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".fragment.FragmentB">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
[fragment_b_item.xml]
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:tools="http://schemas.android.com/tools"
android:paddingTop="8dp"
android:paddingBottom="8dp"
android:paddingLeft="15dp"
android:layout_marginTop="4dp"
android:layout_marginBottom="4dp"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:orientation="horizontal"
android:background="@drawable/border_a">
<TextView
android:id="@+id/tvTitle"
tools:text="Hello Title"
android:layout_width="80dp"
android:layout_height="match_parent"
android:textColor="@color/black"
android:textSize="20sp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingLeft="15dp"
android:paddingRight="15dp" >
<TextView
android:id="@+id/tvBody"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="14sp"
tools:text="Hello Body"
android:textAlignment="center"/>
<TextView
android:id="@+id/tvTime"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textSize="14sp"
tools:text="Hello Time"
android:textAlignment="center"/>
</LinearLayout>
</LinearLayout>
[fragment_c.xml]
<FrameLayout
<\FrameLayout
[res > drawable > border_a.xml]
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#FFD0D0"></solid>
<stroke android:width="3dp" android:color="#FF8484"/>
<corners android:radius="15dp"/>
</shape>
Posted on February 27, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
November 29, 2024