WebView를 스크롤하면 툴바 숨기기

 

CoordinatorLayout 과 NestedScrollView 사용

 

 

build.gradle (:app)

1
2
3
    implementation 'androidx.appcompat:appcompat:1.1.0'
 
 

- Material Design 라이브러리를 추가

 

 

styles.xml

1
2
3
4
5
6
7
8
9
10
11
12
<resources>
 
    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>
 
</resources>
 
 

- 툴바를 레이아웃 xml에 추가할 것이므로 styles에서는 액션바가 없는 스타일을 상속한다

 

 

activity_main.xml

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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
<?xml version="1.0" encoding="utf-8"?>
<!--
CoordinatorLayout : 부모뷰-자식뷰 , 자식뷰들간의 여러 인터렉션을 지원하는 컨테이너
NestedScrollView : 한 화면에 여러개의 스크롤 사용
 
fitsSystemWindows : status bar와 ui가 안겹치도록 조정 (뷰가 상태바와 소프트키 영역을 제외한 영역까지만 차지한다)
-->
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:context=".MainActivity">
 
 
        android:fitsSystemWindows="true"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
 
        <!--
        layout_scrollFlags : AppBarLayout 및 하위의 스크롤 동작 담당
            scroll :  내용과 같이 스크롤, 툴바를 다시 볼려면 스크롤을 위로 끝까지 올려야함
            enterAlways : 맨위에 없어도 위로 스크롤시 바로 툴바가 보임
            enterAlwaysCollapsed : enterAlways와 동작이 비슷하지만 스크롤을 위로 끝까지 올려야 전체뷰가 보임 (스크롤하면 툴바도 같이 스크롤되어 안보임)
            exitUntilCollapsed : 아래/위로 스크롤시 축소된 툴바가 보이고 스크롤을 위로 끝까지 올려야 전체뷰가 보임 (스크롤해도 축소된 툴바가 보임)
            snap : 툴바가 위쪽에서 얼마나 떨어져 있는지에 따라 숨겨지거나 보여짐
         -->
            android:layout_width="match_parent"
            android:layout_height="?android:attr/actionBarSize"
            app:layout_scrollFlags="scroll|enterAlways"
            app:contentInsetStart="0dp"
            app:contentInsetEnd="0dp"
            app:contentInsetLeft="0dp"
            app:contentInsetRight="0dp"
            app:contentInsetStartWithNavigation="0dp">
 
            <LinearLayout
                android:paddingLeft="8dp"
                android:layout_width="match_parent"
                android:layout_height="match_parent">
                <TextView
                    android:text="툴바"
                    android:textSize="16dp"
                    android:textColor="#ffffff"
                    android:layout_gravity="center_vertical"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content" />
            </LinearLayout>
 
 
 
 
    <!-- layout_behavior : 자식뷰의 변화 상태를 부모뷰/다른 자식뷰한테 전달 (여기서는 스크롤했을 경우 다른 자식뷰에게 전달한다) -->
        android:layout_width="match_parent"
        android:layout_height="match_parent">
 
        <LinearLayout
            android:orientation="vertical"
            android:layout_width="match_parent"
            android:layout_height="match_parent">
 
            <WebView
                android:id="@+id/webView"
                android:layout_width="match_parent"
                android:layout_height="wrap_content" />
 
        </LinearLayout>
 
 
 
 
 

- 아래로 스크롤하면 툴바가 사라졌다가 위로 스크롤하면 툴바가 나타난다

 

 

MainActivity.java

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
 
 
public class MainActivity extends AppCompatActivity {
 
    // ui
    WebView webView;
 
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        webView = (WebView)findViewById( R.id.webView );
        webView.setNetworkAvailable( true );
 
        WebSettings settings = webView.getSettings();
        settings.setJavaScriptEnabled( true );
 
        webView.setWebChromeClient( new WebChromeClient() );
        webView.setWebViewClient( new WebViewClient() );
 
        webView.loadUrl( "https://www.naver.com");
    }
}
 
 

- 테스트를 위해 웹뷰에 네이버를 띄운다

 

 

결과

처음에는 툴바가 보였다가 아래로 스크롤하면 툴바가 사라졌다가 위로 조금만 스크롤해도 툴바가 다시 보인다

Glide 라이브러리로 gif이미지 로딩 

 

github : https://github.com/bumptech/glide

 

 

build.gradle (:app)

1
2
3
4
5
    // Glide
    // annotationProcessor : annotation processor classpath 에서 compile processor classpath를 분리하여 빌드 성능개선
    annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'
 
  • glide 라이브러리 추가

 

 

MainActivity.java

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
 
 
 
public class MainActivity extends AppCompatActivity {
 
    ImageView imgGif;
 
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        imgGif = (ImageView)findViewById( R.id.img_gif );
 
        Glide.with( this )
                .asGif()    // GIF 로딩
                .load( R.raw.loading )
                .diskCacheStrategy( DiskCacheStrategy.RESOURCE )    // Glide에서 캐싱한 리소스와 로드할 리소스가 같을때 캐싱된 리소스 사용
                .into( imgGif );
    }
}
 
 
  • GIF 이미지를 raw 폴더에 넣음

 

그외 glide 라이브러리 함수

  • override() : 지정한 크기로 이미지 사이즈 설정

  • placeholder() : 이미지가 로딩할 동안 보여줄 기본 이미지

  • error() : 이미지 로딩 실패시 보여줄 에러 이미지

 

 

activity_main.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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"
    android:padding="8dp"
    tools:context=".MainActivity">
 
    <ImageView
        android:id="@+id/img_gif"
        android:layout_centerInParent="true"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
 
</RelativeLayout>
 
 

 

 

결과

Retrofit2 예제

안전한 타입의 HTTP Client 라이브러리로 Android 및 Java 애플리케이션에서 사용합니다

최소요구사항 : Java 8+ or Android API 21+

 

github : https://github.com/square/retrofit

 

 

build.gradle (:app)

1
2
3
4
    // retrofit2
    implementation group: 'com.squareup.retrofit2', name: 'retrofit', version: '2.8.1'
    implementation group: 'com.squareup.retrofit2', name: 'converter-gson', version: '2.8.1' // JSON을 직렬화
    implementation group: 'com.google.code.gson', name: 'gson', version: '2.8.6' // 직렬화된 JSON을 객체로 역직렬화
  • Retrofit2 라이브러리 추가

 

 

AndroidManifest.xml

1
<uses-permission android:name="android.permission.INTERNET" />
  • 인터넷 사용 권한 추가

 

 

ApiInterface.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 
public interface ApiInterface {
 
    // base_url + "api/login" 으로 POST 통신
    @POST("api/login")
    Call<ResLoginData> requestPostLogin(@Body ReqLoginData reqLoginData );   // @Body : request 파라미터
 
    // base_url + "api/users" 으로 GET 통신
    @GET("api/users")
    Call<ResUsersData> requestGetUsersDetail( @Query(value = "page", encoded = trueString page );   // @Query : url에 쿼리 파라미터 추가, encoded - true
 
}
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
  • HTTP 통신 인터페이스

 

 

HttpClient.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import retrofit2.Retrofit;
 
public class HttpClient {
 
    private static Retrofit retrofit;
 
    // Http 통신을 위한 Retrofit 객체반환
    public static Retrofit getRetrofit() {
        if( retrofit == null )
        {
            Retrofit.Builder builder = new Retrofit.Builder();
            builder.baseUrl( "https://reqres.in/" );
            builder.addConverterFactory( GsonConverterFactory.create() );  // 받아오는 Json 구조의 데이터를 객체 형태로 변환
 
            retrofit = builder.build();
        }
 
        return retrofit;
    }
}
 
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
  • Retrofit 객체를 생성

 

 

ReqLoginData.java

1
2
3
4
5
6
7
8
9
10
11
// api/login 요청 데이터
public class ReqLoginData {
 
    String email;
    String password;
 
    public ReqLoginData( String email, String password ) {
        this.email = email;
        this.password = password;
    }
}
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
  • api/login 통신의 요청 객체

 

 

ResLoginData.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
 
import androidx.annotation.NonNull;
 
// api/login 응답 데이터
public class ResLoginData {
 
    @Expose
    String token;
 
    @NonNull
    @Override
    public String toString() {
        return "[ResLoginData] token=" + token;
    }
}
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
  • api/login 통신의 응답 객체

  • api/login 통신 결과값을 ResLoginData 객체에 맵핑한다

 

 

ResUsersData.java

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
60
61
62
63
64
65
66
67
68
69
 
 
import androidx.annotation.NonNull;
 
// api/users 응답 데이터
public class ResUsersData {
 
    @Expose
    int page;
    @Expose
    @SerializedName("per_page")
    int perPage;
    @Expose
    int total;
    @Expose
    @SerializedName("total_pages")
    int totalPages;
    @Expose
    List<Data> data;
    @Expose
    Ad ad;
 
 
    public class Data {
        int id;
        String email;
        @SerializedName("first_name")
        String firstName;
        @SerializedName("last_name")
        String lastName;
        String avatar;
 
        @NonNull
        @Override
        public String toString() {
            return "{id=" + id + " , email=" + email + " , firstName=" + firstName + " , lastName=" + lastName + " , avatar}";
        }
    }
 
    public class Ad {
        String company;
        String url;
        String text;
 
        @NonNull
        @Override
        public String toString() {
            return "{company=" + company + " , url=" + url + " , text=" + text + "}";
        }
    }
 
    @Override
    public String toString() {
        String str = "[ResUsersData] page=" + page + " , perPage=" + perPage + " , total=" + total + " , totalPages=" + totalPages + " , data= [";
        forint i=0; i<data.size(); i++ ) {
            str += data.get(i).toString();
            if( i < data.size()-1 ) {
                str += ",";
            }
        }
        str += "]";
        str += " , ad=" + ad.toString();
 
        return str;
    }
}
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
  • api/users 통신의 응답 객체

  • api/users 통신 결과값을 ResUsersData 객체에 맵핑한다

 

 

MainActivity.java

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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
 
import retrofit2.Callback;
import retrofit2.Response;
 
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
 
    private static String TAG = "MainActivity";
 
    ApiInterface api;
 
    // ui
    Button btnGet;
    Button btnPost;
    TextView txtResult;
 
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
 
        btnGet = (Button)findViewById( R.id.btnGet );
        btnGet.setOnClickListener( this );
        btnPost = (Button)findViewById( R.id.btnPost );
        btnPost.setOnClickListener( this );
        txtResult = (TextView)findViewById( R.id.txtResult );
 
        api = HttpClient.getRetrofit().create( ApiInterface.class );
    }
 
    @Override
    public void onClick(View view) {
        switch ( view.getId() ) {
            case R.id.btnPost:
                txtResult.setText("");
                requestPost();
                break;
 
            case R.id.btnGet:
                txtResult.setText("");
                requestGet();
                break;
        }
    }
 
    // POST 통신요청
    public void requestPost() {
        ReqLoginData reqLoginData = new ReqLoginData( "eve.holt@reqres.in" , "cityslicka" );
        Call<ResLoginData> call = api.requestPostLogin( reqLoginData );
 
        // 비동기로 백그라운드 쓰레드로 동작
        call.enqueue( new Callback<ResLoginData>() {
            // 통신성공 후 텍스트뷰에 결과값 출력
            @Override
            public void onResponse(Call<ResLoginData> call, Response<ResLoginData> response) {
                txtResult.setText( response.body().toString() );    // body() - API 결과값을 객체에 맵핑
            }
 
            @Override
            public void onFailure(Call<ResLoginData> call, Throwable t) {
                txtResult.setText( "onFailure" );
            }
        } );
    }
 
    // GET 통신요청
    public void requestGet() {
        Call<ResUsersData> call = api.requestGetUsersDetail( "2" );
 
        // 비동기로 백그라운드 쓰레드로 동작
        call.enqueue(new Callback<ResUsersData>() {
            // 통신성공 후 텍스트뷰에 결과값 출력
            @Override
            public void onResponse(Call<ResUsersData> call, Response<ResUsersData> response) {
                txtResult.setText( response.body().toString() );
            }
 
            // 통신실패
            @Override
            public void onFailure(Call<ResUsersData> call, Throwable t) {
                txtResult.setText( "onFailure" );
            }
        });
    }
}
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
  • POST통신과 GET통신 결과값을 TextView에 출력

 

 

activity_main.xml

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
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
 
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
 
        <Button
            android:id="@+id/btnPost"
            android:text="POST"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
 
        <Button
            android:id="@+id/btnGet"
            android:text="GET"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
 
    </LinearLayout>
 
    <TextView
        android:id="@+id/txtResult"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
 
 
</LinearLayout>
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter

 

 

결과

+ Recent posts