一、动态加载布局的技巧
1.使用限定符
修改 FragmentAvtivty 中 activity_main.xml 的代码:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<fragment
android:id="@+id/left_fragment"
android:name="com.example.a28222.fragmentteat.LeftFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
在 res 下新建 layout-large 文件夹,在这个文件夹下面新建一个布局,也叫做 activity_main.xml ,代码:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
android:id="@+id/left_fragment"
android:name="com.example.a28222.fragmentteat.LeftFragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
/>
<fragment
android:id="@+id/right_fragment"
android:name="com.example.a28222.fragmentteat.RightFragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="3"
/>
</LinearLayout>
layout/activtiy_main.xml 中有一个碎片,即单页模式,layout-large/activtiy_main.xml 中有两个碎片,即双页模式。large 就是一个限定符,屏幕被认为是 large 的设备就会加载 layout-large 文件夹下的布局,小屏幕设备则还是会加载 layout 文件夹下的布局。
#将 MainActivtiy 中 replaceFragment() 方法里的代码注释掉再运行程序
#此方法只在 Android 3.2 之前的版本生效
2.使用最小宽度限定符
新建 layout-sw600dp 文件夹,在这个文件夹下新建 activtiy_main.xml 布局
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
android:id="@+id/left_fragment"
android:name="com.example.a28222.fragmentteat.LeftFragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
/>
<fragment
android:id="@+id/right_fragment"
android:name="com.example.a28222.fragmentteat.RightFragment"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="3"
/>
</LinearLayout>
当屏幕宽度大于等于 600dp 时,此布局就会生效。
手机:
平板:
二、碎片的实践——简易版的新闻应用
新建项目 FragmentNewsTest 。
添加依赖:
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
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:24.2.1'
testCompile 'junit:junit:4.12'
compile'com.android.support:recyclerview-v7:24.2.1' //添加的依赖
}
新建新闻的实体类 News :
public class News {
private String title;
private String content;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}
新建 news_content_frag.xml 作为新闻内容的布局:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="@+id/visibility_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:visibility="invisible">
<TextView
android:id="@+id/news_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="10dp"
android:textSize="20sp"
/>
<!-- padding 边距-->
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#000"
/>
<TextView
android:id="@+id/news_content"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:padding="15dp"
android:textSize="18sp"
/>
</LinearLayout>
<!--实现用细线分隔title和content-->
<View
android:layout_width="1dp"
android:layout_height="match_parent"
android:layout_alignParentLeft="true"
android:background="#000"
/>
</RelativeLayout>
用 view 实现分隔标题与内容的功能:
在这里插入代码片public class NewsContentFragment extends Fragment {
private View view;
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
view = inflater.inflate(R.layout.news_cintent_frag,container,false);
return view;
}
//refresh方法用于把新闻的标题和内容显示在界面上
public void refresh(String newsTitle,String newsContent){
View visibilityLayout = view.findViewById(R.id.visibility_layout);
visibilityLayout.setVisibility(View.VISIBLE);
TextView newsTitleText = (TextView)view.findViewById(R.id.news_title);
TextView newsContentText = (TextView)view.findViewById(R.id.news_content);
newsTitleText.setText(newsTitle); //刷新新闻的标题
newsContentText.setText(newsContent); //刷新新闻的内容
}
}
前面新闻内容的碎片和布局都是双页模式中使用的,还需要创建一个单页模式中使用的活动。
com.example.fragmentnewstest / New / Activtiy / Empty Activtiy , 新建NewsContentActivtiy ,将布局命名为 news_content.xml。
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<fragment
android:id="@+id/news_content_fragment"
android:name="com.example.a28222.fragmentnewstest.NewsContentFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<!--
在布局中引用 NewsContentFragment
相当于把 news_content_frag 的布局内容自动加了进来
体现了代码的复用性
-->
</LinearLayout>
修改 NewsContentActivtiy 中的代码:
public class NewsContentAcitivty extends AppCompatActivity {
public static void actionStart(Context context,String newsTitle,String newsContent){
Intent intent = new Intent(context,NewsContentAcitivty.class);
intent.putExtra("news_title",newsTitle);
intent.putExtra("news_content",newsContent);
context.startActivity(intent);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.news_content);
//获取传入的新闻标题
String newsTitle = getIntent().getStringExtra("news_title");
//获取传入的新闻内容
String newsContent = getIntent().getStringExtra("news_content");
NewsContentFragment newsContentFragment = (NewsContentFragment)
getSupportFragmentManager().findFragmentById(R.id.news_content_fragment);
//刷新 NewsContentFragment 界面
newsContentFragment.refresh(newsTitle,newsContent);
}
}
创建 news_title_frag.xml 作为显示新闻列表的布局:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.RecyclerView
android:id="@+id/news_title_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
新建 news_item.xml 作为 RecyclerView 的子项布局:
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/news_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxLines="1"
android:ellipsize="end"
android:textSize="18sp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:paddingTop="15dp"
android:paddingBottom="10dp"
/>
<!--
android:maxLine 设置为1表示让这个 TextView 只能单行显示
android:ellipsize 用于设定当文本内容超出控件宽度时,文本的缩略方式,此处指定尾部缩略
-->
#子项布局的 所有代码 如上所示
新建 layout_sw600dp 文件夹,在下面新建一个 activity_main.xml 文件:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
android:id="@+id/news_title_fragment"
android:name="com.example.a28222.fragmentnewstest.NewsTitleFragment"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="match_parent"/>
<FrameLayout
android:id="@+id/news_content_layout"
android:layout_weight="3"
android:layout_width="0dp"
android:layout_height="match_parent">
<fragment
android:id="@+id/news_content_fragment"
android:name="com.example.a28222.fragmentnewstest.NewsContentFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</FrameLayout>
</LinearLayout>
新建 NewsTitleFragment 作为展示新闻列表的碎片,并添加一个内部类 NewsAdapter 作为 RecyclerView 的适配器,同时向 RecyclerView 中填充数据:
public class NewsTitleFragment extends Fragment {
private boolean isTwoPane;
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.news_title_frag, container, false);
//填充数据代码
RecyclerView newsTitleRecyclerView = (RecyclerView)view.findViewById
(R.id.news_title_recycler_view);
LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());
newsTitleRecyclerView.setLayoutManager(layoutManager);
NewsAdapter adapter = new NewsAdapter(getNews());
newsTitleRecyclerView.setAdapter(adapter);
return view;
}
private List<News> getNews(){
List<News> newsList = new ArrayList<>();
for (int i = 1; i <= 50; i++){
News news = new News();
news.setTitle("this is news title"+i);
news.setContent(getRandomLengthContent("this is news content"+i+"."));
newsList.add(news);
}
return newsList;
}
private String getRandomLengthContent(String content){
Random random = new Random();
int length = random.nextInt(20)+1;
StringBuilder builder = new StringBuilder();
for (int i = 0; i < length; i++){
builder.append(content);
}
return builder.toString();
}
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (getActivity().findViewById(R.id.news_content_layout) != null) {
isTwoPane = true; //可以找到 news_content_layout 布局时为双页模式
} else {
isTwoPane = false; //找不到 news_content_layout 布局时为单页模式
}
}
//填充数据代码
//适配器代码
class NewsAdapter extends RecyclerView.Adapter<NewsAdapter.ViewHolder> {
private List<News> mNewsList;
class ViewHolder extends RecyclerView.ViewHolder {
TextView newsTitleText;
public ViewHolder(View view) {
super(view);
newsTitleText = (TextView) view.findViewById(R.id.news_title);
}
}
public NewsAdapter(List<News> newsList) {
mNewsList = newsList;
}
public ViewHolder onCreateViewHolder(ViewGroup parent,int viewType){
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.news_item,parent,false);
final ViewHolder holder = new ViewHolder(view);
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
News news = mNewsList.get(holder.getAdapterPosition());
if(isTwoPane){
NewsContentFragment newsContentFragment =
(NewsContentFragment) getFragmentManager()
.findFragmentById(R.id.news_content_fragment);
newsContentFragment.refresh(news.getTitle(),news.getContent());
}
else {
NewsContentAcitivty.actionStart(getActivity(),news.getTitle(),news.getContent());
}
}
});
return holder;
}
public void onBindViewHolder(ViewHolder holder,int position){
News news = mNewsList.get(position);
holder.newsTitleText.setText(news.getTitle());
}
public int getItemCount(){
return mNewsList.size();
}
}
//适配器代码
}
手机运行效果:
、
平板运行效果:
小结:把动态加载布局和碎片以及学过的 UI 知识整合了起来,觉得对适配器的掌握相当不够,目前还做不到不看书自己敲实例,说明对看过的东西理解太少,还停留在表面,没有融会贯通完全消化。