와챠의 우당탕탕 코딩 일기장

[안드로이드] 가로 슬라이드 리사이클러뷰 본문

코딩 일기장/Android(Kotlin)

[안드로이드] 가로 슬라이드 리사이클러뷰

minWachya 2021. 7. 31. 17:48
반응형

이건 걍... 말할 것도 없음

android:orientation="horizontal" 만 추가하면 됨....

끝임........

덜덜


갑자기 가로 슬라이드 리사이클러뷰가 만들고 싶어서 만들어본 건데

너무 간단해서... 머쓱하다.

그래도 만들었으니 일단 올려봄.

 

그리고 레이아웃 매니저 설정도 좀 다르게 해줬다.

그동안은 RecyclerView의 layoutManager 설정해주는 거를 kt에서 코드로

weatherRecyclerView1.layoutManager = LinearLayoutManager(this@MainActivity)

이렇게 했는데

 

이번엔 xml에서 아래코드를 추가하는 방식으로 해봤다. 코드도 깔끔해지고 좋은 듯?

app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"


실행 결과 : 분홍색 부분이 가로 슬라이드

 

하늘색 부분 및 날씨 정보 가져와서 뷰 설정하는 부분은 여기서

https://min-wachya.tistory.com/163

 

[안드로이드] 최신 기상청 단기예보 API 활용하기(초단기예보, Json)

올해 1학기 때 과제로 기상청 동네 예보 API를 사용한 적이 있었는데... 7월 초에 이런 메일이 왔다. 동네 예보 API가 종료된다고... 물론 단기 예보 단위가 상세화 되는 건 좋다~ 기존에 있던 코드

min-wachya.tistory.com


avtivity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
android:gravity="center"
android:orientation="vertical">
<TextView
android:id="@+id/tvDate"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="mm/dd의 날씨"
android:textSize="30sp"
android:textColor="@color/black"
android:layout_margin="10dp"
android:gravity="center"/>
<TextView
android:id="@+id/tvError"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="에러 : "
android:textSize="30sp"
android:textColor="@color/black"
android:layout_margin="10dp"
android:gravity="center"
android:visibility="gone"/>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/weatherRecyclerView1"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/weatherRecyclerView2"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
<Button
android:id="@+id/btnRefresh"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="새로고침"/>
</LinearLayout>

item_list_weather1.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#ffccdd"
android:orientation="vertical"
android:gravity="center"
android:padding="10dp"
android:layout_margin="10dp">
<ImageView
android:id="@+id/imgWeather"
android:layout_width="60dp"
android:layout_height="60dp"
android:src="@drawable/sun"/>
<TextView
android:id="@+id/tvTemp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="온도"
android:textColor="@color/black"
android:textSize="24sp"/>
<TextView
android:id="@+id/tvHumidity"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="습도"
android:textColor="@color/black"
android:textSize="14sp"/>
<TextView
android:id="@+id/tvTime"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="HHmm"
android:textColor="@color/black"
android:textSize="30sp"/>
</LinearLayout>

MainActivity.kt : 날씨 api 정보 받아와서 리사이클러뷰 설정하기

package com.example.myweathertest2
import android.graphics.Point
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.os.Looper
import android.util.Log
import android.view.View
import android.widget.Button
import android.widget.TextView
import android.widget.Toast
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.example.myweathertest2.Adapter.WeatherAdapter1
import com.example.myweathertest2.Adapter.WeatherAdapter2
import com.example.myweathertest2.Model.ModelWeather
import com.google.android.gms.location.LocationCallback
import com.google.android.gms.location.LocationRequest
import com.google.android.gms.location.LocationResult
import com.google.android.gms.location.LocationServices
import retrofit2.Call
import retrofit2.Response
import java.text.SimpleDateFormat
import java.util.*
// 메인 액티비티
class MainActivity : AppCompatActivity() {
lateinit var weatherRecyclerView1 : RecyclerView // 날씨 리사이클러 뷰(가로 슿라이드, 분홍)
lateinit var weatherRecyclerView2 : RecyclerView // 날씨 리사이클러 뷰(세로 슿라이드, 하늘)
lateinit var tvDate : TextView
lateinit var base_date : String // 발표 일자
lateinit var base_time : String // 발표 시각
private var curPoint : Point? = null // 현재 위치의 격자 좌표를 저장할 포인트
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
tvDate = findViewById(R.id.tvDate) // 오늘 날짜 텍스트뷰
weatherRecyclerView1 = findViewById(R.id.weatherRecyclerView1) // 날씨 리사이클러 뷰(가로 슿라이드, 분홍)
weatherRecyclerView2 = findViewById(R.id.weatherRecyclerView2) // 날씨 리사이클러 뷰(세로 슿라이드, 하늘)
val btnRefresh = findViewById<Button>(R.id.btnRefresh) // 새로고침 버튼
// xml 에서 설정 : app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
// // 리사이클러 뷰1(가로 슿라이드) 매니저 설정
// weatherRecyclerView1.layoutManager = LinearLayoutManager(this@MainActivity)
// // 리사이클러 뷰2(세로 슿라이드) 매니저 설정
// weatherRecyclerView2.layoutManager = LinearLayoutManager(this@MainActivity)
// 내 위치 위경도 가져와서 날씨 정보 설정하기
requestLocation()
// <새로고침> 버튼 누를 때 위치 정보 & 날씨 정보 다시 가져오기
btnRefresh.setOnClickListener {
requestLocation()
}
}
// 날씨 가져와서 설정하기
private fun setWeather(nx : Int, ny : Int) {
// 준비 단계 : base_date(발표 일자), base_time(발표 시각)
// 현재 날짜, 시간 정보 가져오기
val cal = Calendar.getInstance()
base_date = SimpleDateFormat("yyyyMMdd", Locale.getDefault()).format(cal.time) // 현재 날짜
val timeH = SimpleDateFormat("HH", Locale.getDefault()).format(cal.time) // 현재 시각
val timeM = SimpleDateFormat("HH", Locale.getDefault()).format(cal.time) // 현재 분
// API 가져오기 적당하게 변환
base_time = Common().getBaseTime(timeH, timeM)
// 현재 시각이 00시이고 45분 이하여서 baseTime이 2330이면 어제 정보 받아오기
if (timeH == "00" && base_time == "2330") {
cal.add(Calendar.DATE, -1).toString()
base_date = SimpleDateFormat("yyyyMMdd", Locale.getDefault()).format(cal.time)
}
// 날씨 정보 가져오기
// (한 페이지 결과 수 = 60, 페이지 번호 = 1, 응답 자료 형식-"JSON", 발표 날싸, 발표 시각, 예보지점 좌표)
val call = ApiObject.retrofitService.GetWeather(60, 1, "JSON", base_date, base_time, nx, ny)
// 비동기적으로 실행하기
call.enqueue(object : retrofit2.Callback<WEATHER> {
// 응답 성공 시
override fun onResponse(call: Call<WEATHER>, response: Response<WEATHER>) {
if (response.isSuccessful) {
// 날씨 정보 가져오기
val it: List<ITEM> = response.body()!!.response.body.items.item
// 현재 시각부터 1시간 뒤의 날씨 6개를 담을 배열
val weatherArr = arrayOf(ModelWeather(), ModelWeather(), ModelWeather(), ModelWeather(), ModelWeather(), ModelWeather())
// 배열 채우기
var index = 0
val totalCount = response.body()!!.response.body.totalCount - 1
for (i in 0..totalCount) {
index %= 6
when(it[i].category) {
"PTY" -> weatherArr[index].rainType = it[i].fcstValue // 강수 형태
"REH" -> weatherArr[index].humidity = it[i].fcstValue // 습도
"SKY" -> weatherArr[index].sky = it[i].fcstValue // 하늘 상태
"T1H" -> weatherArr[index].temp = it[i].fcstValue // 기온
else -> continue
}
index++
}
// 각 날짜 배열 시간 설정
for (i in 0..5) weatherArr[i].fcstTime = it[i].fcstTime
// 리사이클러 뷰1(가로 슿라이드, 분홍)에 데이터 연결
weatherRecyclerView1.adapter = WeatherAdapter1(weatherArr)
// 리사이클러 뷰2(세로 슿라이드, 하늘)에 데이터 연결
weatherRecyclerView2.adapter = WeatherAdapter2(weatherArr)
// 토스트 띄우기
Toast.makeText(applicationContext, it[0].fcstDate + ", " + it[0].fcstTime + "의 날씨 정보입니다.", Toast.LENGTH_SHORT).show()
}
}
// 응답 실패 시
override fun onFailure(call: Call<WEATHER>, t: Throwable) {
val tvError = findViewById<TextView>(R.id.tvError)
tvError.text = "api fail : " + t.message.toString() + "\n 다시 시도해주세요."
tvError.visibility = View.VISIBLE
Log.d("api fail", t.message.toString())
}
})
}
// 내 현재 위치의 위경도를 격자 좌표로 변환하여 해당 위치의 날씨정보 설정하기
private fun requestLocation() {
val locationClient = LocationServices.getFusedLocationProviderClient(this@MainActivity)
try {
// 나의 현재 위치 요청
val locationRequest = LocationRequest.create()
locationRequest.run {
priority = LocationRequest.PRIORITY_HIGH_ACCURACY
interval = 60 * 1000 // 요청 간격(1초)
}
val locationCallback = object : LocationCallback() {
// 요청 결과
override fun onLocationResult(p0: LocationResult?) {
p0?.let {
for (location in it.locations) {
// 현재 위치의 위경도를 격자 좌표로 변환
curPoint = Common().dfs_xy_conv(location.latitude, location.longitude)
// 오늘 날짜 텍스트뷰 설정
tvDate.text = SimpleDateFormat("MM월 dd일", Locale.getDefault()).format(Calendar.getInstance().time) + "날씨"
// nx, ny지점의 날씨 가져와서 설정하기
setWeather(curPoint!!.x, curPoint!!.y)
}
}
}
}
// 내 위치 실시간으로 감지
locationClient?.requestLocationUpdates(locationRequest, locationCallback, Looper.myLooper())
} catch (e : SecurityException) {
e.printStackTrace()
}
}
}
view raw MainActivity.kt hosted with ❤ by GitHub

WeatherAdapter.kt : 받아온 날씨 정보 배열로 아이템 뷰 설정하기

package com.example.myweathertest2.Adapter
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.example.myweathertest2.Model.ModelWeather
import com.example.myweathertest2.R
class WeatherAdapter1 (var items : Array<ModelWeather>) : RecyclerView.Adapter<WeatherAdapter1.ViewHolder>() {
// 뷰 홀더 만들어서 반환, 뷰릐 레이아웃은 list_item_weather1.xml
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): WeatherAdapter1.ViewHolder {
val itemView = LayoutInflater.from(parent.context).inflate(R.layout.item_list_weather1, parent, false)
return ViewHolder(itemView)
}
// 전달받은 위치의 아이템 연결
override fun onBindViewHolder(holder: WeatherAdapter1.ViewHolder, position: Int) {
val item = items[position]
holder.setItem(item)
}
// 아이템 갯수 리턴
override fun getItemCount() = items.count()
// 뷰 홀더 설정
inner class ViewHolder(itemView : View) : RecyclerView.ViewHolder(itemView) {
fun setItem(item : ModelWeather) {
val imgWeather = itemView.findViewById<ImageView>(R.id.imgWeather) // 날씨 이미지
val tvTemp = itemView.findViewById<TextView>(R.id.tvTemp) // 온도
val tvHumidity = itemView.findViewById<TextView>(R.id.tvHumidity) // 습도
val tvTime = itemView.findViewById<TextView>(R.id.tvTime) // 시각
imgWeather.setImageResource(getWeatherImage(item.sky))
tvTemp.text = item.temp + "°"
tvHumidity.text = "습도 : ${item.humidity}"
tvTime.text = item.fcstTime
}
}
fun getWeatherImage(sky : String) : Int {
// 하늘 상태
return when(sky) {
"1" ->R.drawable.sun // 맑음
"3" -> R.drawable.very_cloudy // 구름 많음
"4" -> R.drawable.cloudy // 흐림
else -> R.drawable.ic_launcher_foreground // 오류
}
}
}

리사이클러뷰 orientation를 horizontal로 바꾸니까 화면이

item0

item1

item2 <이게 아니라

item0 item1 item2 < 이렇게 된 거가ㅋㅋㅋ(당연함

신기햇음^^

반응형
Comments