【Android】DataBindingとかRecyclerViewとか
はじめに
前回までは主にカメラの映像をプレビューとして表示したり、画像として保存したりしていました。
今回は、映像にかけるフィルター(Mono、Negativeなど)を選択するための画面を、DataBindingやRecyclerViewを使って作成した時(libwvm.soが開けない
ちょっと脇道に逸れますが、Nexus5Xでデバッグをする際気になっていたのですが、以下のようなエラーメッセージが表示されていました。 動作としては特に問題なさそうだったのですが、やはり内容的には気になる…。 libwvm.so自体はオーディオのドライバ関連のファイルのようなので、今回はシャッター音を鳴らすためのMediaActionSoundに絡んで発生したものと考えられます。 前から気にはなっていたDataBinding。せっかくなので取り入れてみることにしました。 Beta版の頃と違って、現在はDataBindingを使うには プロジェクト > app にあるbuild.gradleに以下を加えて、DataBindingを有効にしてやるだけです。 今回はまず手始めに、「findViewById」を置き換えることにします。 CameraのFilterなどを選択するボタンをToolbar上に設置しようと考えたのですが、
プレビュー用のTextureViewと重ねて表示するため透明にしたいと思います。 ということで調べてみたのですが、特別なことは何もなく、ただ背景色に透明度を与えるだけでしたw Lollipopから追加されたRecyclerViewを使って、Filterが選択できるようにしてみました。 ※以下などを読むと本当はListViewでできないかを検討すべきなのだとは思いますが、何よりRecyclerViewを使ってみたいという気持ちがあったのでこちらを選んでいます。 RecyclerViewを使用するには、build.gradleに以下を追加します。 表示する値のセットやUI部分を設定するAdapterを作成します。 Adapterができれば、後は表示するだけです。 だいぶサンプルコードを丸写しにしているところが多いですが、とりあえず表示できるようになりました。
ただ、このままだとどのItemがClickされたかがわかるだけで、CameraへのFilterのセットができません。 次回はその辺りを扱う予定です。
E/WVMExtractor: Failed to open libwvm.so: dlopen failed: library "libwvm.so" not found
ということでググッてみたところ、端末固有の問題のようです。DataBindingを使う
準備
build.gradle
~省略~
android {
~省略~
dataBinding {
enabled = true
}
}
~省略~
layout-land-v17/activity_camera2.xml
< ?xml version="1.0" encoding="utf-8"? >
< < data >
< variable name="camera2" type="jp.cameratest.Camera2Activity" / >
< /data >
< RelativeLayout
android:layout_width='match_parent'
android:layout_height='match_parent' >
< jp.cameratest.PreviewTextureView
android:id='@+id/texture_preview_camera2'
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
/ >
< android.support.v7.widget.Toolbar
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/toolbar_camera2"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:minHeight="40dp"
android:background="#0F000000" / >
< Button
android:layout_width='wrap_content'
android:layout_height='wrap_content'
android:text='@string/btn_taking_photo'
android:id='@+id/btn_taking_photo_camera2'
android:layout_centerVertical="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true" / >
< /RelativeLayout >
< /~省略~
import jp.cameratest.databinding.ActivityCamera2Binding;
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public class Camera2Activity extends AppCompatActivity {
~省略~
private ActivityCamera2Binding binding;
~省略~
@Override
protected void onCreate(Bundle savedInstanceState) {
~省略~
binding = (ActivityCamera2Binding)DataBindingUtil.setContentView(this, R.layout.activity_camera2);
binding.btnTakingPhotoCamera2 != null){
binding.btnTakingPhotoCamera2.setOnClickListener(
(View v) ->{
takePicture();
}
);
}
~省略~
透明なToolbar
toolbar_camera2.xml
< android.support.v7.widget.Toolbar
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/toolbar_camera2"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:minHeight="50dp"
android:title=""
android:background="#0F000000" / >
RecyclerViewを使う
せっかくなので、↑で追加したDataBindingを使用します。準備
build.gradle
~省略~
dependencies {
~省略~
compile 'com.android.support:recyclerview-v7:24.0.0-beta1'
~省略~
}
~省略~
Adapterの作成
recycler_item_filter.xml
< ?xml version="1.0" encoding="utf-8"? >
< layout xmlns:android="http://schemas.android.com/apk/res/android" >
< data >
< variable
name="filterclass"
type="jp.cameratest.FilterListAdapter.FilterClass" >
< /variable >
< /data >
< LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
< TextView
android:id="@+id/listitem_view_filter"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="30dp"
android:padding="20dp"
android:layout_marginBottom="2dp"
android:textColor="#FFFFFF"
android:background="#3F000000"
android:text="@{filterclass.filterName}"/ >
< /LinearLayout >
< /layout >
FilterListAdapter.java
import android.annotation.TargetApi;
import android.databinding.BaseObservable;
import android.databinding.Bindable;
import android.databinding.DataBindingUtil;
import android.databinding.ViewDataBinding;
import android.hardware.camera2.CaptureRequest;
import android.os.Build;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import java.util.ArrayList;
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public class FilterListAdapter extends RecyclerView.Adapter
Fragmentから呼び出して表示する
fragment_select_filter.xml
< ?xml version="1.0" encoding="utf-8"? >
< layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/fragment_select_filter_container" >
< data >
< variable name="selectfilter" type="jp.cameratest.SelectFilterFragment" / >
< /data >
< FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
< android.support.v7.widget.RecyclerView
android:id="@+id/recycler_selectfilter"
android:scrollbars="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerVertical="true"
android:padding="30dp"
app:layoutManager="LinearLayoutManager"
/ >
< /FrameLayout >
< /layout >
SelectFilterFragment.java
import android.os.Bundle;
import android.app.Fragment;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import jp.cameratest.databinding.FragmentSelectFilterBinding;
public class SelectFilterFragment extends Fragment {
protected FilterListAdapter adapter;
public SelectFilterFragment() {
// Required empty public constructor
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_select_filter, container, false);
FragmentSelectFilterBinding binding = FragmentSelectFilterBinding.bind(rootView);
int scrollPosition = 0;
// スクロールした状態でActivityが破棄された場合はスクロール位置を直前の状態に戻す.
if (binding.recyclerSelectfilter.getLayoutManager() != null) {
scrollPosition = ((LinearLayoutManager) binding.recyclerSelectfilter.getLayoutManager())
.findFirstCompletelyVisibleItemPosition();
}
binding.recyclerSelectfilter.scrollToPosition(scrollPosition);
adapter = new FilterListAdapter();
// RecyclerViewにFilterListAdapterをセットする.
binding.recyclerSelectfilter.setAdapter(adapter);
return rootView;
}
}
次回
参考
libwvm.so
DataBinding
Toolbar
RecyclerView