1. 程式人生 > >創建列表明細應用1-使用fragment

創建列表明細應用1-使用fragment

line aps idg 展示 closed public 裏來 androidm 權威指南

筆記自《Android編程權威指南第二版》

第七章,創建一個列表明細應用

技術分享

fragment是一種控制器對象,activity可委派它完成一些任務,這些任務通常就是管理用戶界面。(管理用戶界面的fragment又稱UI fragment。它自己也產生布局文件)

利用fragment,可輕松實現選擇不同的列表項就顯示對應的明細視圖Activity負責以一個明細fragment替換另一個明細fragment

技術分享

托管可以這樣理解,activity在其視圖層級裏提供一處位置來放置fragment的視圖。fragment本身不具有在屏幕上顯示視圖的能力。

技術分享

添加支持庫:


dependencies {
compile fileTree(include: [‘*.jar‘], dir: ‘libs‘)
androidTestCompile(‘com.android.support.test.espresso:espresso-core:2.2.2‘, {
exclude group: ‘com.android.support‘, module: ‘support-annotations‘
})
compile ‘com.android.support:appcompat-v7:26.+‘
compile ‘com.android.support.constraint:constraint-layout:1.0.0-alpha8‘
testCompile ‘junit:junit:4.12‘
compile ‘com.android.support:support-v4:26.0.0-alpha1‘
compile ‘com.android.support:recyclerview-v7:26.0.0-alpha1‘
}

項目結構:

技術分享

Crime實體類:

技術分享
package com.homelink.testcriminal;

import java.util.Date;
import java.util.UUID;

/**
 * Created by ysc on 2017/9/30.
 
*/ public class Crime { private UUID mId; private String mTitle; private Date mDate; private boolean mSolved; public Crime() { mId = UUID.randomUUID(); mDate = new Date(); } public UUID getId() { return mId; } public String getTitle() { return mTitle; } public void setTitle(String title) { mTitle = title; } public Date getDate() { return mDate; } public void setDate(Date date) { mDate = date; } public boolean isSolved() { return mSolved; } public void setSolved(boolean solved) { mSolved = solved; } }
View Code

SingleFragmentActivity抽象基類,用於CrimeActivity , CrimeListActivity。而這兩個Activity又分別創建各自的Fragment

技術分享
package com.homelink.testcriminal;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;

/**
 * Created by ysc on 2017/9/30.
 */

public abstract class SingleFragmentActivity extends FragmentActivity {

    protected abstract Fragment createFragment();

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_fragment);
        FragmentManager fm = getSupportFragmentManager();
        Fragment fragment = fm.findFragmentById(R.id.fragment_container);
        if (fragment == null) {
            fragment = createFragment();
            fm.beginTransaction()
                    .add(R.id.fragment_container, fragment)
                    .commit();
        }
    }


}
View Code

CrimeActitiy.java

技術分享
package com.homelink.testcriminal;

import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.os.Bundle;

public class CrimeActivity extends SingleFragmentActivity {

    @Override
    protected Fragment createFragment() {
        return new CrimeFragment();
    }
}
View Code

CrimeListActivity.java

技術分享
package com.homelink.testcriminal;

import android.support.v4.app.Fragment;

/**
 * Created by ysc on 2017/9/30.
 */

public class CrimeListActivity extends SingleFragmentActivity {

    @Override
    protected Fragment createFragment() {
        return new CrimeListFragment();
    }
}
View Code

activity_fragment.xml 的layout,用於托管fragment。很簡單,就只放了一個FrameLayout,用於承載Fragment

技術分享
<?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="com.homelink.testcriminal.CrimeActivity">

    <FrameLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/fragment_container"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        />

</LinearLayout>
View Code

fragment_crime.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"
    android:orientation="vertical"
    >
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/crime_title_label"
        style="?android:listSeparatorTextViewStyle"
        />
    <EditText android:id="@+id/crime_title"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="16dp"
        android:layout_marginRight="16dp"
        android:hint="@string/crime_title_hint"
        />
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/crime_details_label"
        style="?android:listSeparatorTextViewStyle"
        />
    <Button android:id="@+id/crime_date"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="16dp"
        android:layout_marginRight="16dp"
        />
    <CheckBox android:id="@+id/crime_solved"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="16dp"
        android:layout_marginRight="16dp"
        android:text="@string/crime_solved_label"
        />
</LinearLayout>
View Code

技術分享技術分享

橫向:

技術分享
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/crime_title_label"
        style="?android:listSeparatorTextViewStyle"
        />
    <EditText android:id="@+id/crime_title"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="16dp"
        android:layout_marginRight="16dp"
        android:hint="@string/crime_title_hint"
        />


    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/crime_details_label"
        style="?android:listSeparatorTextViewStyle"
        />
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="16dp"
        android:layout_marginRight="16dp" >
        <Button
            android:id="@+id/crime_date"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1" />
        <CheckBox
            android:id="@+id/crime_solved"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="@string/crime_solved_label" />
    </LinearLayout>

</LinearLayout>
View Code

CrimeFragment.java控制器,展示數據

技術分享
package com.homelink.testcriminal;

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;

/**
 * Created by ysc on 2017/9/30.
 */

public class CrimeFragment extends Fragment {
    private Crime mCrime;
    private EditText mTitleField;

    private Button mDateButton;
    private CheckBox mSolvedCheckBox;


    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mCrime = new Crime();

    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View v = inflater.inflate(R.layout.fragment_crime, container, false);

        mTitleField = (EditText)v.findViewById(R.id.crime_title);
        mTitleField.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(
                    CharSequence s, int start, int count, int after) {
                    // This space intentionally left blank
            }
            @Override
            public void onTextChanged(
                    CharSequence s, int start, int before, int count) {
                mCrime.setTitle(s.toString());
            }
            @Override
            public void afterTextChanged(Editable s) {
                // This one too
            }
        });

        mDateButton = (Button)v.findViewById(R.id.crime_date);
        mDateButton.setText(mCrime.getDate().toString());
        mDateButton.setEnabled(false);



        return v;
    }
}
View Code

技術分享

列表項的控制CrimeListFragment.java:

技術分享
package com.homelink.testcriminal;


import android.os.Bundle;
import android.support.v4.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 android.widget.CheckBox;
import android.widget.TextView;
import android.widget.Toast;

import java.util.List;

/**
 * Created by ysc on 2017/9/30.
 */

public class CrimeListFragment extends Fragment {

    private RecyclerView mCrimeRecyclerView;


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_crime_list, container, false);
        mCrimeRecyclerView = (RecyclerView) view.findViewById(R.id.crime_recycler_view);
        mCrimeRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));

        updateUI();

        return view;
    }



    private CrimeAdapter mAdapter;
    private void updateUI() {
        CrimeLab crimeLab = CrimeLab.get(getActivity());
        List<Crime> crimes = crimeLab.getCrimes();

        mAdapter = new CrimeAdapter(crimes);
        mCrimeRecyclerView.setAdapter(mAdapter);
    }


    private class CrimeHolder extends RecyclerView.ViewHolder implements View.OnClickListener {

        private Crime mCrime;

        private TextView mTitleTextView;
        private TextView mDateTextView;
        private CheckBox mSolvedCheckBox;

        public CrimeHolder(View itemView) {
            super(itemView);

            itemView.setOnClickListener(this);
            mTitleTextView = (TextView) itemView.findViewById(R.id.list_item_crime_title_text_view);
            mDateTextView = (TextView) itemView.findViewById(R.id.list_item_crime_date_text_view);
            mSolvedCheckBox = (CheckBox)itemView.findViewById(R.id.list_item_crime_solved_check_box);
        }



        public void BindCrime(Crime crime){
            mCrime = crime;
            mTitleTextView.setText(mCrime.getTitle());
            mDateTextView.setText(mCrime.getDate().toString());
            mSolvedCheckBox.setChecked(mCrime.isSolved());
        }

        @Override
        public void onClick(View view) {
            Toast.makeText(getActivity(), mCrime.getTitle() + " clicked!", Toast.LENGTH_SHORT).show();
        }
    }
    private class CrimeAdapter extends RecyclerView.Adapter<CrimeHolder> {
        private List<Crime> mCrimes;
        public CrimeAdapter(List<Crime> crimes) {
            mCrimes = crimes;
        }

        @Override
        public CrimeHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            LayoutInflater layoutInflater = LayoutInflater.from(getActivity());
            View view = layoutInflater.inflate(R.layout.list_item_crime, parent, false);
            return new CrimeHolder(view);
        }
        @Override
        public void onBindViewHolder(CrimeHolder holder, int position) {
            Crime crime = mCrimes.get(position);
            //holder.mTitleTextView.setText(crime.getTitle());
            holder.BindCrime(crime);
        }
        @Override
        public int getItemCount() {
            return mCrimes.size();
        }
    }



}
View Code

數據從哪裏來,單例的CrimeLab.java

技術分享
package com.homelink.testcriminal;

import android.content.Context;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

/**
 * Created by ysc on 2017/9/30.
 */

public class CrimeLab {

    private static CrimeLab sCrimeLab;
    public static CrimeLab get(Context context) {
        if (sCrimeLab == null) {
            sCrimeLab = new CrimeLab(context);
        }
        return sCrimeLab;
    }
    private CrimeLab(Context context) {
        initCrimes();
    }



    private List<Crime> mCrimes;
    private void initCrimes(){
        mCrimes = new ArrayList<>();
        for (int i = 0; i < 100; i++) {
            Crime crime = new Crime();
            crime.setTitle("Crime #" + i);
            crime.setSolved(i % 2 == 0); // Every other one
            mCrimes.add(crime);
        }
    }

    public List<Crime> getCrimes() {
        return mCrimes;
    }
    public Crime getCrime(UUID id) {
        for (Crime crime : mCrimes) {
            if (crime.getId().equals(id)) {
                return crime;
            }
        }
        return null;
    }





}
View Code

如果是顯示列表呢,使用recyclerview,fragment_crime_list.xml布局:

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.RecyclerView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/crime_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>

其中列表項:list_item_crime.xml:

技術分享
<?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="wrap_content">

    <CheckBox
        android:id="@+id/list_item_crime_solved_check_box"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:padding="4dp"/>

    <TextView
        android:id="@+id/list_item_crime_title_text_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_toLeftOf="@id/list_item_crime_solved_check_box"
        android:textStyle="bold"
        android:padding="4dp"
        tools:text="Crime Title"/>

    <TextView
        android:id="@+id/list_item_crime_date_text_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_toLeftOf="@id/list_item_crime_solved_check_box"
        android:layout_below="@id/list_item_crime_title_text_view"
        android:padding="4dp"
        tools:text="Crime Date"/>

</RelativeLayout>
View Code

技術分享

當然先修改一下AndroidManifest.xml文件:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.homelink.testcriminal">

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">

<activity android:name=".CrimeListActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".CrimeActivity">

</activity>
</application>

</manifest>

運行:

技術分享

創建列表明細應用1-使用fragment