인라인(inline) 키워드는 자바에서는 제공하지 않는 코틀린만의 키워드입니다. 이러한 인라인 키워드를 이용하여 함수를 만들고 이를 잘 활용한..
Tistroy 에 게시된 글을 crawling 을 통해 cardview 형태로 만들어보겠습니다.
전체적인 UI는 아래 게시글을 재사용하겠습니다.
https://kakaroo.tistory.com/57
Tistory 게시글의 소스는 아래와 같습니다.
Viewer에 구성될 요소들은 카테고리, 카테고리 URL, 게시글 제목, 게시글 날짜, 게시글 URL, 게시글 본문 입니다.
티스토리의 게시글들을 PageNo 또는 검색어로 검색하거나, 전체 글을 카테고리 별로 분류해서 게시하려 합니다.
<Category recycler view 구성>
<LinearLayout
android:orientation="vertical"
android:background="#FFFFFF"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="16dp">
<LinearLayout
android:orientation="horizontal"
android:background="#FFFFFF"
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/tv_category"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="4"
android:layout_margin="4dp"
android:textSize="18sp"
android:textStyle="bold"
android:textColor="#000000" />
<TextView
android:id="@+id/tv_topicNum"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="0.1"
android:layout_marginTop="10dp"
android:layout_marginRight="12dp"
android:textColor="#000000"
android:textSize="12sp" />
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv_articles"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
<Category class>
data class Category(var name: String, var articles: ArrayList<Article>)
<Article view>
<androidx.cardview.widget.CardView
android:id="@+id/card_view"
android:layout_margin="4dp"
android:layout_gravity="center"
android:layout_width="match_parent"
android:layout_height="wrap_content"
card_view:cardCornerRadius="4dp">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="2dp">
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_margin="2dp">
<ImageView
android:id="@+id/iv_thumb"
android:layout_width="70dp"
android:layout_height="60dp"
android:src="@drawable/news_thumb_jpg"/>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="2dp">
<TextView
android:id="@+id/tv_title"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_marginTop="0dp"
android:layout_marginLeft="2dp"
android:layout_marginRight="2dp"
android:layout_marginBottom="0dp"
android:ellipsize="marquee"
android:textStyle="bold"
android:lines="3"
android:layout_gravity="right"
android:text="Kotlin? Java?"
android:textSize="10dp"/>
<TextView
android:id="@+id/tv_date"
android:layout_width="42dp"
android:layout_height="16dp"
android:layout_marginTop="2dp"
android:layout_marginLeft="8dp"
android:layout_marginRight="0dp"
android:layout_marginBottom="4dp"
android:ellipsize="marquee"
android:singleLine="true"
android:layout_gravity="right"
android:text="2022.04.01"
android:textSize="8dp"/>
</LinearLayout>
</LinearLayout>
<TextView
android:id="@+id/tv_summary"
android:layout_width="110dp"
android:layout_height="60dp"
android:layout_marginLeft="4dp"
android:layout_marginTop="4dp"
android:layout_marginRight="8dp"
android:layout_marginBottom="2dp"
android:ellipsize="end"
android:maxLines="4"
android:text="인라인(inline) 키워드는 자바에서는 제공하지 않는 코틀린만의 키워드입니다. 이러한 인라인 키워드를 이용하여 함수를 만들고 이를 잘 활용한다면"
android:textSize="12dp" />
</LinearLayout>
</androidx.cardview.widget.CardView>>
<Article data class>
data class Article(val idx: Int, val categoryName: String, var title: String, var date: String,
val categoryUrl: String, val articleUrl: String, val imgUrl: String, var summary: String)
각각의 포스팅은 아래와 같이 구성이 됩니다.
<article class="article-type-common article-type-thumbnail">
<a href="/69" class="link-article">
<p class="thumbnail" has-thumbnail="1" style="background-image:url('https://blog.kakaocdn.net/dn/nja5F/btryciPbvtV/z3WgxG3Y4WLTGKqnL1FeRK/img.png')" >
<img src="https://blog.kakaocdn.net/dn/nja5F/btryciPbvtV/z3WgxG3Y4WLTGKqnL1FeRK/img.png" class="img-thumbnail" role="presentation">
</p>
</a>
<div class="article-content">
<a href="/69" class="link-article">
<strong class="title">inline 함수</strong>
<p class="summary">인라인(inline) 키워드는 자바에서는 제공하지 않는 코틀린만의 키워드입니다. 이러한 인라인 키워드를 이용하여 함수를 만들고 이를 잘 활용한다면 다양한 이득을 얻을 수 있..</p>
</a>
<div class="box-meta">
<a href="/category/Kotlin" class="link-category">Kotlin</a>
<span class="date">2022.04.01</span>
<span class="reply">
<s_rp_count></s_rp_count>
</span>
</div>
</div>
</article>
JSoup을 넘겨줄 tag class를 정의합니다.
data class ArticlesTag(var articleTag: String = Common.SELECTOR_ARTICLE_SYNTAX,
var categoryTag: String = Common.SELECTOR_CATEGORY_SYNTAX,
var articleUrlTag: String = Common.SELECTOR_ARTICLUEURL_SYNTAX,
var titleTag: String = Common.SELECTOR_TITLE_SYNTAX,
var dateTag: String = Common.SELECTOR_DATE_SYNTAX,
var imageTag: String = Common.SELECTOR_IMAGE_SYNTAX,
var summaryTag: String = Common.SELECTOR_SUMMARY_SYNTAX) {
init {
if(articleTag == "") this.articleTag = Common.SELECTOR_ARTICLE_SYNTAX
if(categoryTag == "") this.categoryTag = Common.SELECTOR_CATEGORY_SYNTAX
if(articleUrlTag == "") this.articleUrlTag = Common.SELECTOR_ARTICLUEURL_SYNTAX
if(titleTag == "") this.titleTag = Common.SELECTOR_TITLE_SYNTAX
if(dateTag == "") this.dateTag = Common.SELECTOR_DATE_SYNTAX
if(imageTag == "") this.imageTag = Common.SELECTOR_IMAGE_SYNTAX
if(summaryTag == "") this.summaryTag = Common.SELECTOR_SUMMARY_SYNTAX
}
}
JSoup에서는 해당 tag를 가지고 parsing을 합니다.
val contentElements: Elements = doc.select(articlesTag.articleTag)
for ((i, elem) in contentElements.withIndex()) {
val category = elem.select(articlesTag.categoryTag).text()
val articleUrl = elem.select(articlesTag.articleUrlTag).first().attr(Common.HREF_TAG)
val title = elem.select(articlesTag.titleTag).text()
val date = elem.select(articlesTag.dateTag).text()
val categoryUrl = elem.select(articlesTag.categoryTag).first().attr(Common.HREF_TAG)
val imageUrl = elem.select(articlesTag.imageTag).attr(Common.SRC_TAG)
val summary = elem.select(articlesTag.summaryTag).text()
//mCategorySet.add(category)
mArticleList.add(Article(i, category, title, date, url+categoryUrl, url+articleUrl, imageUrl, summary))
티스토리 마다 CSS 를 다르게 사용하기 때문에 그에 따라 HTML tag도 다르게 됩니다.
JSoup을 통해 분류할 tag 는 설정으로 사용자가 직접 설정할 수 있게 하겠습니다.
<PreferenceScreen 설정>
<PreferenceCategory app:title="@string/category_header"
app:iconSpaceReserved="false"
app:key="url_category_key">
<EditTextPreference
app:key="url_input_key"
app:title="@string/blog_url"
app:useSimpleSummaryProvider="false"
app:summary=""
app:iconSpaceReserved="false"/>
</PreferenceCategory>
<PreferenceCategory app:title="@string/category_tag"
app:iconSpaceReserved="false"
app:key="tag_category_key">
<EditTextPreference
app:key="article_tag_key"
app:title="@string/article_tag_name"
app:useSimpleSummaryProvider="false"
app:summary="article"
app:iconSpaceReserved="false"/>
<EditTextPreference
app:key="category_tag_key"
app:title="@string/category_tag_name"
app:useSimpleSummaryProvider="false"
app:summary="a.link-category"
app:iconSpaceReserved="false"/>
<EditTextPreference
app:key="articleLink_tag_key"
app:title="@string/link_tag_name"
app:useSimpleSummaryProvider="false"
app:summary="a.link-article"
app:iconSpaceReserved="false"/>
<EditTextPreference
app:key="title_tag_key"
app:title="@string/title_tag_name"
app:useSimpleSummaryProvider="false"
app:summary=".title"
app:iconSpaceReserved="false"/>
<EditTextPreference
app:key="date_tag_key"
app:title="@string/date_tag_name"
app:useSimpleSummaryProvider="false"
app:summary=".date"
app:iconSpaceReserved="false"/>
<EditTextPreference
app:key="image_tag_key"
app:title="@string/image_tag_name"
app:useSimpleSummaryProvider="false"
app:summary="img.img-thumbnail"
app:iconSpaceReserved="false"/>
<EditTextPreference
app:key="summary_tag_key"
app:title="@string/summary_tag_name"
app:useSimpleSummaryProvider="false"
app:summary=".summary"
app:iconSpaceReserved="false"/>
</PreferenceCategory>
<PreferenceCategory app:title="@string/category_page"
app:iconSpaceReserved="false"
app:key="page_category_key">
<EditTextPreference
app:key="page_max_num_key"
app:title="@string/article_maxnum"
app:useSimpleSummaryProvider="false"
app:summary="50"
app:iconSpaceReserved="false"/>
</PreferenceCategory>
HTML tag에 따른 설정방법 도움말도 ImageView 로 하나 만들어 보았습니다.
해당 이미지를 Dialog에 생성하고, 이미지가 작기 때문에 zoon-in 기능도 넣어보겠습니다.
<custom_dialog.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:id="@+id/customDialog"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/tv_hint1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hint1_text" />
<TextView
android:id="@+id/tv_hint2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hint2_text" />
<View
android:background="@color/black"
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginLeft="2dp"
android:layout_marginRight="2dp"/>
<com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
android:id="@+id/imgView_Hint"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:src="@drawable/settings_hint"
android:layout_marginTop="2dp"
android:layout_marginBottom="2dp"
android:layout_marginLeft="2dp"
android:layout_marginRight="2dp"/>
</LinearLayout>
zoon-in 이 가능한 image view를 사용하기 위해 SubsamplingScaleImageView library를 추가해줍니다.
implementation 'com.davemorrissey.labs:subsampling-scale-image-view:3.10.0'
코드에는 아래와 같이 리소스만 적용해주면 간단하게 확대가 가능한 image view를 만들수 있습니다.
//Image zoom in-out
val imageView: SubsamplingScaleImageView = mDialog.findViewById(R.id.imgView_Hint)
imageView.setImage(ImageSource.resource(R.drawable.settings_hint))
확장함수 (Extension Function) (0) | 2022.04.14 |
---|---|
코루틴(Coroutine) (0) | 2022.04.03 |
inline 함수 (0) | 2022.04.01 |
enum class, sealed class (0) | 2022.03.31 |
sequence (0) | 2022.03.27 |