Home | 简体中文 | 繁体中文 | 杂文 | Github | 知乎专栏 | Facebook | Linkedin | Youtube | 打赏(Donations) | About
知乎专栏

113.8. Containers

113.8.1. CardView

113.8.1.1. 实现圆角 ImageView

			
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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">

    <androidx.cardview.widget.CardView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:cardCornerRadius="10dp"
        app:cardElevation="0dp"
        tools:ignore="MissingConstraints">

        <ImageView
            android:id="@+id/imageView7"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:scaleType="fitXY"
            app:srcCompat="@drawable/bg_repast_menu" />
    </androidx.cardview.widget.CardView>
</androidx.constraintlayout.widget.ConstraintLayout>			
			
			

113.8.2. RecyclerView

113.8.2.1. 滚动到最底部

			
        linearLayoutManager = new LinearLayoutManager(ContextHolder.getContext());
        linearLayoutManager.setStackFromEnd(true);
        recyclerView.setLayoutManager(linearLayoutManager);
        recyclerView.scrollToPosition(adapter.getItemCount() - 1);
			
			

调用下面函数

			
recyclerView.smoothScrollToPosition(adapter.getItemCount() - 1);			
			
			

其他用法

			
//                        linearLayoutManager.scrollToPositionWithOffset(adapter.getItemCount() - 1, Integer.MIN_VALUE);
//                        linearLayoutManager.scrollToPosition(adapter.getItemCount() - 1);
			
			

113.8.2.2. ItemView 禁止自适应

			
        @NonNull
        @Override
        public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
//            View view = View.inflate(MainApplication.getContext(), R.layout.recycler_view_chat, null); 这种方式,Item 不会100%充满屏幕
            View view = LayoutInflater.from(MainApplication.getContext()).inflate(R.layout.recycler_view_chat, parent, false);
            ViewHolder viewHolder = new ViewHolder(view);
            return viewHolder;
        }
			
			

113.8.2.3. 滚动条

判断是否滑动到顶部/底部:

			
@Override
public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
    if(newState == RecyclerView.SCROLL_STATE_IDLE){//停止滑动
        if(recyclerView.canScrollVertically(1)){
            Log.d(TAG, "滑动到顶部");
        }
        if(recyclerView.canScrollVertically(-1)){
            Log.d(TAG, "滑动到底部");
        }
    }
    super.onScrollStateChanged(recyclerView, newState);
}

recyclerView.canScrollVertically(1);  false表示不能往上滑动,即代表到顶部了;
recyclerView.canScrollVertically(-1); false表示不能往下滑动,即代表到底部了;
			
			

判断滑动方向

			
@Override
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
    if (dy > 0) {//下滑动作
    }

    if (dy < 0) {//上滑动作
    }
    super.onScrolled(recyclerView, dx, dy);
}

			
			

保存滚动条位置

			
// Save state
Parcelable recyclerViewState = recyclerView.getLayoutManager().onSaveInstanceState();

// Todo

// Restore state
recyclerView.getLayoutManager().onRestoreInstanceState(recyclerViewState);
			
			

113.8.2.4. 子视图操作

			
    View view = binding.recyclerView.getChildAt(0);
    TextView textView = view.findViewById(R.id.textViewQuestion);
    textView.setText("Hello");			
			
			

113.8.2.5. 水平布局

			
	LinearLayoutManager linearLayoutManager = new LinearLayoutManager(requireContext(), LinearLayoutManager.HORIZONTAL, false);
	binding.recyclerView.setLayoutManager(linearLayoutManager);
			
			

113.8.2.6. 遍历所有子试图

			
	RecyclerView.LayoutManager layoutManager = binding.loraRecyclerView.getLayoutManager();
    int childCount = layoutManager.getChildCount();
    for (int i = 0; i < childCount; i++) {
        View childView = layoutManager.getChildAt(i);
        TextView nameTextView = childView.findViewById(R.id.nameTextView);
        nameTextView.setBackgroundColor(Color.WHITE);
        nameTextView.setTextColor(Color.BLACK);
    }			
			
			

113.8.3. NavigationView

		
    <com.google.android.material.navigation.NavigationView
        android:id="@+id/navigationView"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        app:headerLayout="@layout/navigation_header"
        app:menu="@menu/navigation" />
		
		
		
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <!--    <group android:checkableBehavior="single">-->
    <!--        <item-->
    <!--            android:id="@+id/fragment_05"-->
    <!--            android:title="界面1" />-->
    <!--        <item-->
    <!--            android:id="@+id/fragment_06"-->
    <!--            android:title="界面2" />-->
    <!--        <item-->
    <!--            android:id="@+id/fragment_07"-->
    <!--            android:title="界面3" />-->
    <!--    </group>-->
    <group android:id="@+id/groupAi">
        <item
            android:id="@+id/fragment_share"
            android:icon="@drawable/menu_community"
            android:title="@string/discovery" />
        <item
            android:id="@+id/menu_story"
            android:icon="@drawable/menu_story"
            android:title="@string/story" />
        <item
            android:id="@+id/menu_chat"
            android:icon="@drawable/menu_chat"
            android:title="@string/chat" />
    </group>
    <group android:id="@+id/debug" android:visible="false">

        <item
            android:id="@+id/fragment_09"
            android:icon="@drawable/menu_like"
            android:title="点赞作品" />
        <item
            android:id="@+id/menu_home"
            android:icon="@drawable/menu_favorites"
            android:title="收藏作品"/>
        <!--    </group>-->
        <!--    <group android:id="@+id/group_two" >-->

        <item
            android:id="@+id/menu_pictur_book"
            android:icon="@drawable/menu_book"
            android:title="@string/pictur_book"
            />

    </group>
    <group android:id="@+id/groupSetting">
        <item
            android:id="@+id/fragment_bind"
            android:icon="@drawable/menu_bind"
            android:title="@string/device" />
        <item
            android:id="@+id/fragment_notification"
            android:icon="@android:drawable/ic_popup_reminder"
            android:title="消息通知" />
        <item
            android:id="@+id/menu_about"
            android:icon="?android:attr/actionModeFindDrawable"
            android:title="@string/about" />

        <item
            android:id="@+id/menu_quit"
            android:icon="@drawable/menu_quit"
            android:title="退出" />
    </group>
</menu>
		
		

113.8.3.1. 菜单的显示/隐藏

菜单项目的显示和隐藏

			
            MenuItem menuItem = findViewById(R.id.debug);
            menuItem.setVisible(true);
			
			

菜单组的显示/隐藏

			
            Menu menuGroup = navigationView.getMenu();
            menuGroup.setGroupVisible(R.id.debug, true);
			
			

113.8.4. 底部导航

只显示图标,不显示文字 app:labelVisibilityMode="unlabeled"

		
            <com.google.android.material.bottomnavigation.BottomNavigationView
                android:id="@+id/nav_view"
                android:layout_width="match_parent"
                android:layout_height="40dp"
                android:background="@android:color/system_neutral2_50"
                app:itemIconTint="@drawable/navigation_view"
                app:labelVisibilityMode="unlabeled"
                app:menu="@menu/bottom_nav_menu"
                tools:ignore="NewApi" />		
		
		
		
.setLabelVisibilityMode(LabelVisibilityMode.LABEL_VISIBILITY_LABELED);
		
		

图标不显示原始颜色

		
setItemIconTintList(null)		
		
		

文字上下移动,app:itemPaddingBottom="15dp",app:itemPaddingTop="0dp"

		
            <com.google.android.material.bottomnavigation.BottomNavigationView
                android:id="@+id/nav_view"
                android:layout_width="match_parent"
                android:layout_height="40dp"
                android:background="@android:color/system_neutral2_50"
                android:gravity="center"
                app:itemPaddingBottom="15dp"
                app:itemTextColor="@color/black"
                app:labelVisibilityMode="labeled"
                app:menu="@menu/bottom_nav_menu"
                tools:ignore="NewApi" />
		
		

113.8.4.1. 选中菜单

			
binding.bottomNavigationView.setSelectedItemId(binding.bottomNavigationView.getMenu().getItem(3).getItemId());			
			
			

113.8.5. TabLayout

113.8.5.1. xml 布局

			
		<com.google.android.material.tabs.TabLayout
                android:id="@+id/tabLayout"
                android:layout_width="match_parent"
                android:layout_height="wrap_content">

                <com.google.android.material.tabs.TabItem
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="消息" />

                <com.google.android.material.tabs.TabItem
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="审核" />
                
            </com.google.android.material.tabs.TabLayout>
            
        <androidx.fragment.app.FragmentContainerView
            android:id="@+id/fragmentContainerViewTabItem"
            android:name="cn.netkiller.student.ui.message.NotificationFullscreenFragment"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:fitsSystemWindows="true" />
			
			

113.8.5.2. OnTabSelectedListener 事件

			
		binding.tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
            // 页面被选中
            @Override
            public void onTabSelected(TabLayout.Tab tab) {
                Log.d(TAG, "onTabSelected: " + tab.getText());
                Fragment fragment = null;
                switch (tab.getPosition()) {
                    // 这里我随便写了两个Fragment
                    case 0:
                        fragment = new NotificationFullscreenFragment();
                        break;
                    case 1:
                        fragment = new AuditFragment();
                        break;
                }

                if (fragment != null) {
                    getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.fragmentContainerViewTabItem, fragment).commit();
                }
            }

            // 页面切换到其他
            @Override
            public void onTabUnselected(TabLayout.Tab tab) {
                Log.d(TAG, "onTabUnselected: " + tab.getText());
            }

            @Override
            public void onTabReselected(TabLayout.Tab tab) {
                Log.d(TAG, "onTabReselected: " + tab.getText());
            }
        });
			
			

113.8.5.3. 防止快速点击切换

			
binding.tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
            private boolean isOnTabSelectedListener = false;

            @Override
            public void onTabSelected(TabLayout.Tab tab) {

                if (isOnTabSelectedListener) {
                    Log.e(TAG, "onTabSelected: 暴击 " + tab.getText());
                    return;
                } else {
                    new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
                        public void run() {
                            isOnTabSelectedListener = false;
                            Log.e(TAG, "Tab 释放");
                        }
                    }, 5000);
                    isOnTabSelectedListener = true;
                }
                Log.d(TAG, "onTabSelected: " + tab.getText());
                Fragment fragment = null;
                switch (tab.getPosition()) {
                    case 0:
                        fragment = new NoticeFragment();
                        break;
                    case 1:
                        fragment = new MessageFragment();
                        break;
                    case 2:
                        fragment = new AuditFragment();
                        break;
                }

                if (fragment != null) {
                    try {
                        if (!isAdded()) return;
//                        requireActivity().getSupportFragmentManager().beginTransaction().replace(R.id.fragmentContainerViewTabItem, fragment).commit();
                        getChildFragmentManager().beginTransaction().replace(R.id.fragmentContainerViewTabItem, fragment).commitAllowingStateLoss();
                    } catch (Exception e) {
                        Log.d(TAG, "Tab 切换出错" + e.getMessage());
                    }

                }
            }

            // 页面切换到其他
            @Override
            public void onTabUnselected(TabLayout.Tab tab) {
                Log.d(TAG, "onTabUnselected: " + tab.getText());
            }

            @Override
            public void onTabReselected(TabLayout.Tab tab) {
                Log.d(TAG, "onTabReselected: " + tab.getText());
            }
        });
			
			

增加间隔时间,并且恢复最后一次点击位置的操作

			
    private void switchTabLayout(int position) {
        Fragment fragment = null;
        switch (position) {
            case 0:
                fragment = new NoticeFragment();
                break;
            case 1:
                fragment = new MessageFragment();
                break;
            case 2:
                fragment = new AuditFragment();
                break;
        }

        if (fragment != null) {
            try {
                if (!isAdded()) return;
//                        requireActivity().getSupportFragmentManager().beginTransaction().replace(R.id.fragmentContainerViewTabItem, fragment).commit();
                getChildFragmentManager().beginTransaction().replace(R.id.fragmentContainerViewTabItem, fragment).commitAllowingStateLoss();
            } catch (Exception e) {
                Log.d(TAG, "Tab 切换出错" + e.getMessage());
            }

        }
    }			
			
		binding.tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
            private final long interval = 1000L;
            private boolean isOnTabSelectedListener = false;
            private int index = 0;

            @Override
            public void onTabSelected(TabLayout.Tab tab) {
                index = tab.getPosition();
                if (isOnTabSelectedListener) {
                    Log.e(TAG, "onTabSelected: 暴击 " + tab.getText() + " 位置: " + index);
                    return;
                } else {
                    new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
                        public void run() {
                            isOnTabSelectedListener = false;
                            switchTabLayout(index);

                            Log.e(TAG, "Tab 释放,并且切换最后一次点击位置: " + index + " - " + tab.getPosition());
                        }
                    }, interval);

                    isOnTabSelectedListener = true;
                }
                Log.d(TAG, "onTabSelected: " + tab.getText());
                switchTabLayout(tab.getPosition());
            }

            // 页面切换到其他
            @Override
            public void onTabUnselected(TabLayout.Tab tab) {
                Log.d(TAG, "onTabUnselected: " + tab.getText());
            }

            @Override
            public void onTabReselected(TabLayout.Tab tab) {
                Log.d(TAG, "onTabReselected: " + tab.getText());
            }
        });	
			
			

113.8.6. ViewPager2

		
    <androidx.viewpager2.widget.ViewPager2
        android:id="@+id/viewPager2"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
		
		

view_page_layout.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="match_parent">

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:text="TextView" />
</LinearLayout>
		
		
		
	private List<String> items = List.of("A", "B", "C");		
		
	@Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        binding.viewPager2.setAdapter(new ViewPagerAdapter());
    }
		
		
		
    public class ViewPagerAdapter extends RecyclerView.Adapter<ViewPagerAdapter.CardViewHolder> {

        @NonNull
        @Override
        public ViewPagerAdapter.CardViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
            return new CardViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.view_page_layout, parent, false));
        }

        @Override
        public void onBindViewHolder(@NonNull ViewPagerAdapter.CardViewHolder holder, int position) {
            holder.textView.setText(items.get(position));
        }

        @Override
        public int getItemCount() {
            return items.size();
        }

        public class CardViewHolder extends RecyclerView.ViewHolder {

            public TextView textView;

            public CardViewHolder(@NonNull View itemView) {
                super(itemView);
                textView = itemView.findViewById(R.id.textView);
            }
        }
    }
		
		

113.8.6.1. ViewPager2 with Fragments

			
    <com.google.android.material.tabs.TabLayout
        android:id="@+id/tabLayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <com.google.android.material.tabs.TabItem
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="推荐" />

    </com.google.android.material.tabs.TabLayout>

    <androidx.viewpager2.widget.ViewPager2
        android:id="@+id/viewPager2"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
			
			
			
package cn.netkiller.student.fragment.library;

import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.viewpager2.adapter.FragmentStateAdapter;

import com.google.gson.Gson;

import java.util.List;

import cn.netkiller.student.cloud.PictureBook;
import cn.netkiller.student.databinding.FragmentLibraryFullscreenBinding;

public class LibraryFullscreenFragment extends Fragment {
    private static final String TAG = LibraryFullscreenFragment.class.getSimpleName();
    private final Gson gson = new Gson();
    private FragmentLibraryFullscreenBinding binding;
    private List<PictureBook.DataResponse.Data> categories;

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater,
                             @Nullable ViewGroup container,
                             @Nullable Bundle savedInstanceState) {

        binding = FragmentLibraryFullscreenBinding.inflate(inflater, container, false);
        return binding.getRoot();

    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        PictureBook pictureBook = new PictureBook();
        pictureBook.category(datas -> {
            categories = datas;
            requireActivity().runOnUiThread(() -> {
                categories.forEach(item -> {
                    var tab = binding.tabLayout.newTab();
                    tab.setText(item.name);
                    binding.tabLayout.addTab(tab);
                });
                binding.viewPager2.setAdapter(new ViewPagerFragmentStateAdapter(this));
            });
        });

    }

    public class ViewPagerFragmentStateAdapter extends FragmentStateAdapter {


        public ViewPagerFragmentStateAdapter(@NonNull Fragment fragment) {
            super(fragment);
        }

        @NonNull
        @Override
        public Fragment createFragment(int position) {
            int id = categories.get(position).id;
            return BookshelfFragment.newInstance(id);
        }

        @Override
        public int getItemCount() {
            return categories.size();
        }
    }

    @Override
    public void onResume() {
        super.onResume();

    }

    @Override
    public void onPause() {
        super.onPause();

    }

    @Override
    public void onDestroy() {
        super.onDestroy();
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        binding = null;
    }
}	
			
			
			
package cn.netkiller.student.fragment.library;

import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;

import cn.netkiller.student.databinding.FragmentBookshelfBinding;

public class BookshelfFragment extends Fragment {
    private static final String TAG = BookshelfFragment.class.getSimpleName();
    private FragmentBookshelfBinding binding;
    private int categoryId;

    public static BookshelfFragment newInstance(int categoryId) {
        BookshelfFragment fragment = new BookshelfFragment();
        Bundle args = new Bundle();
        args.putInt("categoryId", categoryId);
//        args.putString(ARG_PARAM2, param2);
        fragment.setArguments(args);

        return fragment;
    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater,
                             @Nullable ViewGroup container,
                             @Nullable Bundle savedInstanceState) {

        binding = FragmentBookshelfBinding.inflate(inflater, container, false);

        if (getArguments() != null) {
            categoryId = getArguments().getInt("categoryId");
        }
        return binding.getRoot();
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        Log.d(TAG, "Categroy Id: " + categoryId);
        binding.fullscreenContent.setText(categoryId + "");
    }

    @Override
    public void onResume() {
        super.onResume();
    }

    @Override
    public void onPause() {
        super.onPause();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        binding = null;
    }
}	
			
			

113.8.6.2. TabLayout + ViewPager2 + Fragments

			
    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        PictureBook pictureBook = new PictureBook();
        pictureBook.category(datas -> {
            categories = datas;
            requireActivity().runOnUiThread(() -> {
                categories.forEach(item -> {
                    var tab = binding.tabLayout.newTab();
                    tab.setText(item.name);
                    binding.tabLayout.addTab(tab);
                });
                binding.viewPager2.setAdapter(new ViewPagerFragmentStateAdapter(this));
                new TabLayoutMediator(binding.tabLayout, binding.viewPager2, new TabLayoutMediator.TabConfigurationStrategy() {
                    @Override
                    public void onConfigureTab(@NonNull TabLayout.Tab tab, int position) {
                        tab.setText(categories.get(position).name);
                    }
                }).attach();

            });
        });

    }