Android Studio簡單還原微信ui 目標 實現3-4個tab的切換效果 技術需求 activity, xdm, fragment, recyclerview 成果展示 其中聯繫人界面通過recyclerview實現了可以滑動列表 倉庫地址 https://github.com/SmileE ...
Android Studio簡單還原微信ui 目標 實現3-4個tab的切換效果 技術需求 activity, xdm, fragment, recyclerview 成果展示 其中聯繫人界面通過recyclerview實現了可以滑動列表 倉庫地址 https://github.com/SmileEX/wecaht.git
實現過程 主要ui 第一步我們首先把微信的ui主體做出來,即這三個部分 因為中間是動態界面我們先不用寫完,把上下兩個xml編寫完之後就可以創建一個mainlayout.xml將他們拼起來
1 <?xml version="1.0" encoding="utf-8"?> 2 <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 xmlns:app="http://schemas.android.com/apk/res-auto" 4 xmlns:tools="http://schemas.android.com/tools" 5 android:layout_width="match_parent" 6 android:layout_height="match_parent"> 7 8 <include 9 layout="@layout/top" 10 android:id="@+id/topLayout" 11 android:layout_width="match_parent" 12 android:layout_height="wrap_content" 13 app:layout_constraintTop_toTopOf="parent" 14 app:layout_constraintStart_toStartOf="parent" 15 app:layout_constraintEnd_toEndOf="parent"/> 16 17 <androidx.fragment.app.FragmentContainerView 18 android:id="@+id/fragmentContainerView" 19 android:layout_width="0dp" 20 android:layout_height="0dp" 21 app:layout_constraintBottom_toTopOf="@+id/bottomLayout" 22 app:layout_constraintEnd_toEndOf="parent" 23 app:layout_constraintHorizontal_bias="0.496" 24 app:layout_constraintStart_toStartOf="parent" 25 app:layout_constraintTop_toBottomOf="@+id/topLayout" 26 app:layout_constraintVertical_bias="0.448" /> 27 28 <include 29 android:id="@+id/bottomLayout" 30 app:layout_constraintBottom_toBottomOf="parent" 31 app:layout_constraintEnd_toEndOf="parent" 32 app:layout_constraintStart_toStartOf="parent" 33 layout="@layout/bottom" 34 android:layout_width="0dp" 35 android:layout_height="wrap_content" /> 36 37 </androidx.constraintlayout.widget.ConstraintLayout>
然後我們再來編寫其中的fragment,就目前學習進度而言,只需要做到中間頁面可以互相切換fragment即可,不需要對內容進行細節補充
所以在編寫完一個之後另外三個直接cv即可。每一個fragment.xml對應一個fragment.java。
下麵是一個fragment.java和fragment.xml
package com.example.test;
import android.os.Bundle;
import androidx.fragment.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
/**
* A simple {@link Fragment} subclass.
* Use the {@link Fragment1# newInstance} factory method to
* create an instance of this fragment.
*/
public class Fragment1 extends Fragment {
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
// TODO: Rename and change types of parameters
private String mParam1;
private String mParam2;
public Fragment1() {
// Required empty public constructor
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment1, container, false);
}
}
View Code
<?xml version="1.0" encoding="utf-8"?> <FrameLayout 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" tools:context=".Fragment1"> <!-- TODO: Update blank fragment layout --> <TextView android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:text="這是聊天界面" android:textSize="35sp" /> </FrameLayout>
現在我們來將其中一個fragment改進一下來讓它有更多的細節,這裡我把“聯繫人”界面進行了細節擴充,在其中加入了一些小說人物的頭像以及他們的姓名,看起來就像微信里的聯繫人界面
首先在layout中在添加一個xml文件用來使用recyclerview,我將其命名為activity_recycler_view.xml,代碼如下
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <androidx.recyclerview.widget.RecyclerView android:id="@+id/recyclerview" android:layout_width="match_parent" android:layout_height="match_parent"/> </androidx.constraintlayout.widget.ConstraintLayout>
目前我們已經做出了雛形,但是每個主頁都是空白並沒有內容,接下來將其中一個頁面填充一點細節
為了實現如圖的頭像+名字的這種結構,我們還需要創建一個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:background="@android:color/darker_gray" android:layout_margin="8dp" android:orientation="horizontal"> <!-- 這個是頭像 --> <ImageView android:id="@+id/tv_img" android:layout_width="50dp" android:layout_height="50dp" android:textSize="30sp" /> <TextView android:id="@+id/tv_content" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="內容" android:textSize="30sp" /> </LinearLayout>
在ImageView中我們不用給出圖片的路徑,因為我們會在java文件中動態的設置他們
接下來創建一個RecyclerViewAdapter.java, 在Android中,RecyclerView
是一個更強大和靈活的列表視圖組件,用於顯示大量數據,並支持動態添加、刪除和刷新數據。
適配器(Adapter)負責將數據綁定到RecyclerView
上。
定義RecyclerViewAdapter
類:
這個類繼承自RecyclerView.Adapter
,它是用來將數據源(在這裡是mList
和mSrc
)與RecyclerView
控制項進行綁定的。這個構造函數接受三個參數:context
(上下文對象)、src
(包含圖片資源的列表)、和list
(包含文本數據的列表)
1 public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.Myviewholder> { 2 private List<String> mList; 3 private List<Integer> mSrc; 4 private Context context; 5 public RecyclerViewAdapter(Context context, List<Integer> src, List<String> list) { 6 this.mSrc = src; 7 this.mList = list; 8 this.context=context; 9 }
實現onCreateViewHolder
方法:
onCreateViewHolder
方法負責創建並返回新的ViewHolder
對象,它通過LayoutInflater
將定義在R.layout.item
中的佈局實例化為一個View
對象,並將其傳遞給Myviewholder
類的構造函數
1 @NonNull 2 @Override 3 public Myviewholder onCreateViewHolder(@NonNull ViewGroup parent, int viewType){ 4 View view=(View)LayoutInflater.from(parent.getContext()).inflate(R.layout.item,parent,false); 5 Myviewholder myviewholder=new Myviewholder((view)); 6 return myviewholder; 7 }
實現onBindViewHolder
方法:
onBindViewHolder
方法用於將數據綁定到ViewHolder
上,這裡根據position
參數獲取對應位置的圖片資源和文本數據,並設置到ViewHolder
中的ImageView
和TextView
中
1 @Override 2 public void onBindViewHolder(@NonNull Myviewholder holder, int position) { 3 holder.tvimg.setImageResource(mSrc.get(position)); 4 holder.tvContent.setText(mList.get(position)); 5 position++; 6 }
實現getItemCount
方法:
getItemCount
方法返回數據源的大小,告訴RecyclerView
有多少個數據需要顯示
1 @Override 2 public int getItemCount() { 3 return mList.size(); 4 }
定義Myviewholder
內部類:
這個內部類繼承自RecyclerView.ViewHolder
,它持有itemView
的子視圖的引用。在構造函數中,通過itemView.findViewById
方法獲取了R.id.tv_img
和R.id.tv_content
對應的ImageView
和TextView
對象
1 public class Myviewholder extends RecyclerView.ViewHolder{ 2 TextView tvContent; 3 ImageView tvimg; 4 public Myviewholder(@NonNull View itemView) { 5 super(itemView); 6 tvimg=itemView.findViewById((R.id.tv_img)); 7 tvContent=itemView.findViewById(R.id.tv_content); 8 } 9 }
然後創建一個fragment來初始化一些數據並用我們上面自定義的adapter來顯示我們的列表數據
1 public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){ 2 View view= inflater.inflate(R.layout.activity_recycler_view, container, false); 3 context = view.getContext(); 4 InitData(); 5 RecyclerView recyclerView = view.findViewById(R.id.recyclerview); 6 RecyclerViewAdapter adapter = new RecyclerViewAdapter(context, mSrc, mList); 7 recyclerView.setAdapter(adapter); 8 LinearLayoutManager manager = new LinearLayoutManager(context); 9 manager.setOrientation(LinearLayoutManager.VERTICAL); 10 recyclerView.setLayoutManager(manager); 11 recyclerView.addItemDecoration(new DividerItemDecoration(context,LinearLayoutManager.VERTICAL )); 12 return view; 13 }
最後編寫MainActivity.java來完成界面轉換,底部按鈕變化等邏輯
1 package com.example.test; 2 3 import androidx.appcompat.app.AppCompatActivity; 4 import androidx.fragment.app.Fragment; 5 import androidx.fragment.app.FragmentManager; 6 7 import android.view.View; 8 import android.os.Bundle; 9 import android.widget.LinearLayout; 10 import android.widget.ImageButton; 11 12 13 public class MainActivity extends AppCompatActivity implements View.OnClickListener { 14 private LinearLayout linearLayout1, linearLayout2, linearLayout3, linearLayout4; 15 Fragment fragment1,fragment2,fragment3,fragment4; 16 ImageButton img1, img2, img3, img4; 17 FragmentManager manager; 18 int transaction; 19 20 @Override 21 protected void onCreate(Bundle savedInstanceState) { 22 super.onCreate(savedInstanceState); 23 setContentView(R.layout.mainlayout); 24 25 linearLayout1 = findViewById(R.id.chat); 26 linearLayout2 = findViewById(R.id.people); 27 linearLayout3 = findViewById(R.id.moment); 28 linearLayout4 = findViewById(R.id.settings); 29 30 //這些圖片參數用來實現被點擊是底部tab圖標的變化 31 img1 = findViewById(R.id.button1); 32 img2 = findViewById(R.id.button2); 33 img3 = findViewById(R.id.button3); 34 img4 = findViewById(R.id.button4); 35 36 manager = getSupportFragmentManager(); 37 38 fragment1 = new Fragment1(); 39 fragment2 = new settingFragment(); 40 fragment3 = new Fragment3(); 41 fragment4 = new Fragment4(); 42 43 inital(); 44 fragmentHide(); 45 showfragment(fragment1); 46 img1.setImageResource(R.drawable.tab_weixin_pressed); 47 48 linearLayout1.setOnClickListener(this); 49 linearLayout2.setOnClickListener(this); 50 linearLayout3.setOnClickListener(this); 51 linearLayout4.setOnClickListener(this); 52 } 53 54 public void onClick(View view) { 55 /* 56 每次遇到點擊事件時,首先消除以前操作留下的fragmen和imagebutton 57 然後在修改對應的img和fragment 58 */ 59 fragmentHide(); 60 if (view.getId() == R.id.chat) { 61 showfragment(fragment1); 62 img1.setImageResource(R.drawable.tab_weixin_pressed); 63 } else if (view.getId() == R.id.people) { 64 showfragment(fragment2); 65 img2.setImageResource(R.drawable.tab_address_pressed); 66 } else if (view.getId() == R.id.moment) { 67 showfragment(fragment3); 68 img3.setImageResource(R.drawable.tab_find_frd_pressed); 69 } else if (view.getId() == R.id.settings) { 70 showfragment(fragment4); 71 img4.setImageResource(R.drawable.tab_settings_pressed); 72 } 73 } 74 75 private void showfragment(Fragment fragment) { 76 transaction=manager.beginTransaction() 77 .show(fragment) 78 .commit(); 79 } 80 81 //初始化容器內的元素 82 public void inital(){ 83 transaction=manager.beginTransaction() 84 .add(R.id.fragmentContainerView,fragment1) 85 .add(R.id.fragmentContainerView,fragment2) 86 .add(R.id.fragmentContainerView,fragment3) 87 .add(R.id.fragmentContainerView,fragment4) 88 .commit(); 89 } 90 91 //初始化ui顯示,每次程式啟動時自動打開第一個fragment,並且點亮第一個icon 92 public void fragmentHide(){ 93 img1.setImageResource(R.drawable.tab_weixin_normal); 94 img2.setImageResource(R.drawable.tab_address_normal); 95 img3.setImageResource(R.drawable.tab_find_frd_normal); 96 img4.setImageResource(R.drawable.tab_settings_normal); 97 transaction=manager.beginTransaction() 98 .hide(fragment1) 99 .hide(fragment2) 100 .hide(fragment3) 101 .hide(fragment4) 102 .commit(); 103 } 104 }
在這段代碼中,linearLayout1, linearLayout2, linearLayout3, linearLayout4,這些變數會檢測用戶是否點擊,一旦出現點擊事件,程式便會根據點擊的實際情況來改變mainlayout(onclick方法)中androidx.fragment.app.FragmentContainerView的元素,以達到界面互相切換的目的,同時imagebutton變數也會根據點擊來變化(onclick方法),當某個tab處於激活狀態是,該tab對應的按鈕就會自動
亮起,其他按鈕熄滅。
開源地址 https://github.com/SmileEX/wecaht.git