Android基礎知識——開發中遇到的問題

2020-10-19 16:00:27

1.動態控制佈局的位置

在開發時,我們可能需要在同一活動中的不同介面下來改變佈局的位置使得佈局處於一個比較合理的位置。

例如:我們在活動的主介面希望使用者能有沉浸式的體驗,所以我們將我們的佈局延伸到了系統欄中,可是當我們轉換到設定(碎片)的介面時,就很有可能發生系統欄中的圖示,將我們介面上標題列的部分按鈕遮擋的情況。而為了解決這一問題我們就要在程式碼中對佈局位置進行控制了。

程式碼展示:

FrameLayout.LayoutParams layoutParams;
layoutParams=(FrameLayout.LayoutParams) view.findViewById(R.id.choose_layout).getLayoutParams();
if(getActivity() instanceof WeatherActivity){
    //動態控制佈局的margin屬性
    layoutParams.topMargin=50;
}

2.無線電鈕的使用

在開發時,很多時候都會讓使用者選擇讓某一項功能開啟還是關閉,這個時候就需要一個比較美觀的控制元件來實現這一功能了。

效果展示:

程式碼展示:

//宣告依賴
dependencies {
    implementation 'com.github.zcweng:switch-button:0.0.3'
}
//佈局檔案中用法
<com.suke.widget.SwitchButton
    android:id="@+id/switch_button"
    android:layout_gravity="center"
    android:layout_marginLeft="60dp"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />
//邏輯檔案中用法
switchButton.setChecked();//設定控制元件的開關狀態
switchButton.setOnCheckedChangeListener(new SwitchButton.OnCheckedChangeListener() {
    @Override
    public void onCheckedChanged(SwitchButton view, boolean isChecked) {//點選事件
        if(isChecked==true){
            //當控制元件變為true時的邏輯程式碼
        }else if(isChecked==false){
            //當控制元件變為false時的邏輯程式碼
        }
    }
});

3.僅在需要時才顯示佈局

在開發時,我們可能會需要先隱藏部分佈局,然後當使用者執行某一操作後再將這部分佈局顯現出來。為了實現這一功能我給大家介紹兩種方法,併為大家指出它們的利弊。

3.1控制佈局的可見屬性

我們需要先將需隱藏佈局的可見屬性設定為View.GONE,然後在使用者執行某一操作後將可見屬性設定為View.VISIBLE即可輕易實現這一功能。

3.2ViewStub

我們也可以使用ViewStub控制元件來幫助我們實現這一功能。

程式碼展示:

//待隱藏佈局
<?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"
    android:orientation="vertical" >
 
    <EditText
        android:id="@+id/edit_extra1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="20dp"
        android:layout_marginRight="20dp"
        android:hint="Extra field 1" />
 
    <EditText
        android:id="@+id/edit_extra2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="20dp"
        android:layout_marginRight="20dp"
        android:layout_marginTop="10dp"
        android:hint="Extra field 2" />
 
    <EditText
        android:id="@+id/edit_extra3"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="20dp"
        android:layout_marginRight="20dp"
        android:layout_marginTop="10dp"
        android:hint="Extra field 3" />
 
</LinearLayout>
//主介面佈局
<?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"
    android:orientation="vertical" >
 
    <EditText
        android:id="@+id/edit"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="10dp"
        android:layout_marginLeft="20dp"
        android:layout_marginRight="20dp"
        android:layout_marginTop="10dp"
        android:hint="@string/edit_something_here" />
 
    <Button
        android:id="@+id/more"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="right"
        android:layout_marginRight="20dp"
        android:layout_marginBottom="10dp"
        android:text="More" />
    
    <ViewStub 
        android:id="@+id/view_stub"
        android:layout="@layout/profile_extra"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
 
</LinearLayout>
//邏輯程式碼
private EditText editExtra1;
private EditText editExtra2;
private EditText editExtra3;

public void onMoreClick() {//當我們點選more按鈕時執行該函數,即可是實現隱藏佈局的顯示
	ViewStub viewStub = (ViewStub) findViewById(R.id.view_stub);
	if (viewStub != null) {
		View inflatedView = viewStub.inflate();
		editExtra1 = (EditText) inflatedView.findViewById(R.id.edit_extra1);
		editExtra2 = (EditText) inflatedView.findViewById(R.id.edit_extra2);
		editExtra3 = (EditText) inflatedView.findViewById(R.id.edit_extra3);
	}

3.3以上兩種方法的利弊

第一種方法:

  • 優點:邏輯簡單而且控制起來比較靈活。

  • 缺點:耗費資源。雖然把View的初始可見View.GONE但是在Inflate佈局的時候View仍然會被Inflate,也就是說仍然會建立物件,會被範例化,會被設定屬性。也就是說,會耗費記憶體等資源。

第二種方法:

  • 優點:在Inflate佈局的時候,只有ViewStub會被初始化,然後當ViewStub被設定為可見的時候,或是呼叫了ViewStub.inflate()的時候,ViewStub所向的佈局就會被Inflate和範例化,然後ViewStub的佈局屬性都會傳給它所指向的佈局。這樣,就可以使用ViewStub來方便的在執行時,要還是不要顯示某個佈局。這樣也就節省了記憶體資源,實現了佈局的優化。

  • 特點:ViewStub只能Inflate一次,之後ViewStub物件會被置為空。也就是說,某個被ViewStub指定的佈局被Inflate後,就不能再通過ViewStub來控制它了;ViewStub只能用來Inflate一個佈局檔案,而不是某個具體的View,當然也可以把View寫在某個佈局檔案中。

  • 缺點:在程式的執行期間,某個佈局在Inflate後,就不會有變化,除非重新啟動。也就是說,不能再將載入出來的佈局隱藏了;只能控制顯示與隱藏的是佈局檔案,而非某個View。

4.判斷ImageView展示的是哪一張圖片

在開發時,我們有可能要根據ImageView展示的圖片,來決定讓其執行哪一點選事件。而要實現這一功能就需要判斷先ImageView展示的是哪一張圖片。

程式碼展示:

moreImage.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        if(moreImage.getDrawable().getCurrent().getConstantState().equals(ContextCompat.getDrawable(SettingActivity.this,R.drawable.many).getConstantState())){//判斷方法
            //具體邏輯
        }else {
            //具體邏輯
        }
    }
});

5.單選框的使用

在開發時,我們有時需要提供一組選項,來讓使用者選擇一個。而實現這一功能就要利用單選框控制元件了。

程式碼展示:

//佈局檔案
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    
    <RadioGroup
        android:id="@+id/radio_group"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">

        <RadioButton
            android:id="@+id/eight_time"
            android:layout_margin="10dp"
            android:text="8小時"
            android:textSize="20sp"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

        <RadioButton
            android:id="@+id/four_time"
            android:layout_margin="10dp"
            android:text="4小時"
            android:textSize="20sp"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

        <RadioButton
            android:id="@+id/two_time"
            android:layout_margin="10dp"
            android:text="2小時"
            android:textSize="20sp"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

        <RadioButton
            android:id="@+id/one_time"
            android:layout_margin="10dp"
            android:text="1小時"
            android:textSize="20sp"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

    </RadioGroup>

</LinearLayout>
//邏輯程式碼
radioGroup.check();//設定哪一單選框為選中狀態
radioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {//點選事件
    @Override
    public void onCheckedChanged(RadioGroup radioGroup, int i) {
        switch (i){
            case R.id.eight_time:
                //選中後的邏輯程式碼
                break;
            case R.id.four_time:
                //選中後的邏輯程式碼
                break;
            case R.id.two_time:
                 //選中後的邏輯程式碼
                break;
            case R.id.one_time:
                 //選中後的邏輯程式碼
                break;
            default:
        }
    }
}

6.RecyclerView實現側滑刪除

在開發中,我們有時需要實現側滑RecyclerView的某一子項佈局來刪除它的功能。

以下程式碼中省略了RecyclerView的基本實現方法,倘若有讀者還不太清楚,請移步這裡

程式碼展示:

//為RecycleView繫結觸控事件
ItemTouchHelper helper=new ItemTouchHelper(new ItemTouchHelper.Callback() {

    @Override
    public int getMovementFlags(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
    	//首先回撥的方法 返回int表示是否監聽該方向
        int dragFlags = ItemTouchHelper.UP|ItemTouchHelper.DOWN;//拖拽
        int swipeFlags = ItemTouchHelper.LEFT|ItemTouchHelper.RIGHT;//側滑刪除
        return makeMovementFlags(dragFlags,swipeFlags);
    }
    
    @Override
    public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) {
    	//滑動事件
        return false;
    }
    
    @Override
    public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
    	//側滑事件
        nameList.remove(viewHolder.getAdapterPosition());
        myAdapter.notifyItemRemoved(viewHolder.getAdapterPosition());
    }
    
});
helper.attachToRecyclerView(recyclerView);

注意:倘若你還需在側滑事件中刪除資料庫的內容,要將其放在remove函數之前,否則getAdapterPosition()的返回值會發生變化。

7.在活動中處理RecyclerView的點選事件

當我們在處理RecyclerView的點選事件時很有可能還要用到活動中的一些資料,而一般情況下RecyclerView的點選事件是在其介面卡中註冊的,這就使得你可能無法在點選事件中實現某些功能了。而為了解決在活動中處理點選事件這一問題,我們可以利用回撥介面來實現。

程式碼展示:

//定義介面
public interface OnItemClickListener {
    void onItemClick(int position);
}
//在介面卡的點選事件中呼叫該介面中的方法
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {

    private List<Saved> list=new ArrayList<>();
    private OnItemClickListener Listener=null;
    
    public MyAdapter(List<Saved> list, OnItemClickListener Listener){//我們還需要在構造方法傳入該介面
        this.Listener=Listener;
        this.list=list;
    }
    
    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, final int viewType) {
        View view= LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_item,parent,false);
        final ViewHolder viewHolder=new ViewHolder(view);
        view.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Listener.onItemClick(viewHolder.getAdapterPosition());//呼叫介面中的方法
            }
        });
        return viewHolder;
    }

	......
}
//在活動中實現該介面中的方法
OnItemClickListener recyclerListener=new OnItemClickListener() {
    @Override
    public void onItemClick(int position) {
        //具體邏輯程式碼
    }
};