源碼舉例如何優(yōu)化復(fù)雜邏輯UI的類

該文章講解的源碼全憑個人積累的經(jīng)驗編寫,所以如果有大神覺得不好或者有更好的意見希望可以提出來,謝謝!

本文的適讀人群

  • zhongjhATC/AlbumCameraRecorder 過來了解如何更深入的自定義Camera布局
  • 想了解如何優(yōu)化復(fù)雜UI的類
  • 想了解如何封裝父類、抽象類作為組件易于后續(xù)擴展

該源碼類是什么功能,如何復(fù)雜法?

功能可以理解為是微信的拍攝、錄制結(jié)合的界面,甚至支持多圖,多視頻錄制。具體功能可點擊zhongjhATC/AlbumCameraRecorder 查看。
那么我們可以初步理解為有以下幾個核心功能:

  • 圖片功能
  • 視頻功能
  • 拍攝、錄制等功能

以上圖片功能和視頻功能又是只通過一個按鈕觸發(fā),那么很多UI邏輯都會糅合在一個UI類里面。所以,這次代碼優(yōu)化選擇了狀態(tài)模式 + Facade模式。
同時,考慮到更多開發(fā)者使用該庫時會需要擴展不同的邏輯業(yè)務(wù),所以,這些類都要弄成可繼承、可擴展使用的。
讓開發(fā)者更好了解如何使用,就出現(xiàn)了此文章。

我們先直接看優(yōu)化后的CameraFragment如何擴展

  1. 自定義一個CameraFragment,需要繼承BaseCameraFragment,代碼如下:
public class CameraFragment1 extends BaseCameraFragment<CameraStateManagement, BaseCameraPicturePresenter, BaseCameraVideoPresenter> {

    FragmentCamera1Binding mBinding;
    BaseCameraPicturePresenter cameraPicturePresenter = new BaseCameraPicturePresenter(this);
    BaseCameraVideoPresenter cameraVideoPresenter = new BaseCameraVideoPresenter(this);
    CameraStateManagement cameraStateManagement = new CameraStateManagement(this);

    public static CameraFragment1 newInstance() {
        return new CameraFragment1();
    }

    @Override
    public View setContentView(LayoutInflater inflater, ViewGroup container) {
        mBinding = DataBindingUtil.inflate(inflater, R.layout.fragment_camera1,container,false);
        return mBinding.getRoot();
    }

    @Override
    public void initView(View view, Bundle savedInstanceState) {
    }

    /**
     * TODO
     * 覆寫該事件,賦值自定義按鈕事件
     */
    @Override
    protected void initListener() {
        super.initListener();
        mBinding.btnCustom.setOnClickListener(v -> Toast.makeText(getMyContext(), "我是自定義的", Toast.LENGTH_SHORT).show());
    }

    @NonNull
    @Override
    public IChildClickableLayout getChildClickableLayout() {
        return mBinding.rlMain;
    }

    @Nullable
    @Override
    public View getTopView() {
        return mBinding.clMenu;
    }

    @NonNull
    @Override
    public CameraView getCameraView() {
        return mBinding.cameraView;
    }

    @Override
    public RecyclerView getRecyclerViewPhoto() {
        return mBinding.rlPhoto;
    }

    @Nullable
    @Override
    public View[] getMultiplePhotoView() {
        return new View[]{mBinding.vLine1, mBinding.vLine2};
    }

    @NonNull
    @Override
    public PhotoVideoLayout getPhotoVideoLayout() {
        return mBinding.pvLayout;
    }

    @NonNull
    @Override
    public com.zhongjh.albumcamerarecorder.widget.ImageViewTouch getSinglePhotoView() {
        return mBinding.imgPhoto;
    }

    @Nullable
    @Override
    public View getCloseView() {
        return mBinding.imgClose;
    }

    @Nullable
    @Override
    public ImageView getFlashView() {
        return mBinding.imgFlash;
    }

    @Nullable
    @Override
    public ImageView getSwitchView() {
        return mBinding.imgSwitch;
    }

    @NonNull
    @Override
    public CameraStateManagement getCameraStateManagement() {
        return cameraStateManagement;
    }

    @NonNull
    @Override
    public BaseCameraPicturePresenter getCameraPicturePresenter() {
        return cameraPicturePresenter;
    }

    @NonNull
    @Override
    public BaseCameraVideoPresenter getCameraVideoPresenter() {
        return cameraVideoPresenter;
    }

}

從上面代碼看到,我們提供一個View布局(如果默認(rèn)的就已經(jīng)滿足了,就直接使用R.layout.fragment_camera_zjh),然后在一些NonNull標(biāo)記下必須提供不為null的View或者類,接著就可以直接在自己的布局上增加自己想要的View了,想擴展的地方可以覆寫方法添加邏輯。
當(dāng)一個Fragment弄好后,我們需要告訴該庫使用該Fragment,代碼如下:

cameraSetting.setBaseCameraFragment(CameraFragment1.newInstance());

那么在這里就結(jié)束了,當(dāng)然,如果你需要擴展更多的東西,我們需要更深入了解其他類的作用。讓我們繼續(xù)往下看

我們看看優(yōu)化后的代碼包結(jié)構(gòu)

camera -->
         BaseCameraFragment
         adapter-->
         impl-->
         presenter-->
            PicturePresenter 
            VideoPresenter
         state-->
            StateInterface
            StateMode
            CameraStateManagement
            type-->
                PictureComplete
                PictureMultiple
                Preview
                VideoComplete
                VideoIn
                VideoMultiple
                VideoMultipleIn

以表格形式講解每一個包結(jié)構(gòu)

包結(jié)構(gòu) 作用
BaseCameraFragment 一個父類,提供于開發(fā)者繼承擴展該類,該類可認(rèn)為是個大容器,可使用其他類
adapter 顧名思義,只是個adpater,目前只存放顯示多圖的適配器
impl 包含所有接口,主要是用來告訴開發(fā)者都有哪些方法可以擴展使用
presenter 并不是MVP的presenter,別混淆了。該presenter含有picture和video,picture是處理所有有關(guān)圖片UI的邏輯,而video是處理所有有關(guān)視頻UI的邏輯
state 狀態(tài)模式,StateInterface告訴開發(fā)者狀態(tài)類有哪些方法可以擴展使用,StateMode是個實體,CameraStateManagement則是管理當(dāng)前狀態(tài),進行相關(guān)UI邏輯。而type里面的PictureComplete、PictureMultiple…等則是各自狀態(tài)處理他們當(dāng)前狀態(tài)的UI邏輯。

那么了解過后,會發(fā)現(xiàn),其實是三個實現(xiàn)類分解了這個UI類所包含的功能,腦圖:


image.png

接口

接口在這里只起到規(guī)范性作用,單純是讓其他沒接觸過的開發(fā)者可以一目了然了解這些類有什么方法。

這段代碼可以看到實現(xiàn)了兩個接口,區(qū)分兩個接口讓開發(fā)者更好分辨接口的方法屬于哪一類的

public abstract class BaseCameraFragment
        extends BaseFragment implements ICameraView, ICameraFragment 

以表格形式講解每一個接口類

接口 作用 鏈接
ICameraFragment 拍攝界面的接口,主要用于告示開發(fā)者可以使用哪些方法,大部分是關(guān)于View操作的界面邏輯,除了圖片、視頻、實例化View,其他方法都統(tǒng)一在Fragment使用 ICameraFragment
ICameraView 錄制界面規(guī)定view的設(shè)置。對所有View都標(biāo)記了NonNull和Nullable。標(biāo)記了NonNull的View返回是不能為空的,在布局上必須使用這些View,當(dāng)然,也可以繼承View加上你想要的方法 ICameraView
ICameraPicture 拍攝界面的有關(guān)圖片View的接口,控制多圖Adapter也是在這里實現(xiàn) ICameraPicture
ICameraVideo 拍攝界面的有關(guān)視頻View的接口 ICameraVideo
IState 狀態(tài)事件接口,對于不同狀態(tài)下,他們各自的實現(xiàn)不一樣 IState

使用泛型+父類+抽象方法 規(guī)范開發(fā)者使用

從上面得知,我們CameraFragment封裝出了圖片、視頻、狀態(tài)三大類出去,那么如何規(guī)定開發(fā)者必須引用這三大類進來呢?代碼如下:

public abstract class BaseCameraFragment
        <StateManagement extends CameraStateManagement,
                CameraPicture extends BaseCameraPicturePresenter,
                CameraVideo extends BaseCameraVideoPresenter> {
    @NonNull
    public abstract StateManagement getCameraStateManagement();
    @NonNull
    public abstract CameraPicture getCameraPicturePresenter();
    @NonNull
    public abstract CameraVideo getCameraVideoPresenter();  
}

那么在子類繼承BaseCameraFragment得時候,必須實現(xiàn)這三個類

public class CameraFragment1 extends BaseCameraFragment<CameraStateManagement, BaseCameraPicturePresenter, BaseCameraVideoPresenter> {

    BaseCameraPicturePresenter cameraPicturePresenter = new BaseCameraPicturePresenter(this);

    @NonNull
    @Override
    public BaseCameraPicturePresenter getCameraPicturePresenter() {
        return cameraPicturePresenter;
    }  

}

從上面三個實現(xiàn)方法得知,如果你想自定義有關(guān)圖片邏輯或者視頻邏輯,那么需要繼承Presenter擴展你想要的方法后使用它,代碼如下:

public class CameraPicturePresenter extends BaseCameraPicturePresenter {

    public CameraPicturePresenter(BaseCameraFragment<? extends CameraStateManagement, ? extends BaseCameraPicturePresenter, ? extends BaseCameraVideoPresenter> baseCameraFragment) {
        super(baseCameraFragment);
    }

    @Override
    public void takePhoto() {
        super.takePhoto();
        Toast.makeText(baseCameraFragment.getMyContext(), "拍照時觸發(fā)自定義事件!", Toast.LENGTH_SHORT).show();
    }
}

開發(fā)者使用自定義CameraLayout過程碰到的疑問

  • 1.我想動態(tài)加點數(shù)據(jù),這些數(shù)據(jù)都是來自于上一個Activity

    答:可以通過自定義的CameraFragment.setArguments()動態(tài)賦值,也可以使用event之類的,反正就當(dāng)一個普通的fragment使用。

    1. mBinding.imgClose.setOnClickListener(v -> { 
              // 自定義代碼
      })
      
      我想在關(guān)閉前做些事 為什么設(shè)置完監(jiān)聽 關(guān)閉不掉了

    答:因為你關(guān)閉事件覆蓋掉了,要熟悉基類的本身事件。正確做法是使用基類的有關(guān)關(guān)閉事件方法,再加上你的自定義事件。(多了解基類)

寫在最后

那么基本在這里就差不多介紹結(jié)束了,想了解更加具體的做法和源碼的,請下載下面的GitHub源碼鏈接

  1. 覺得好用的歡迎給個Star(GitHub
  2. 發(fā)現(xiàn)任何BUG歡迎留言或者留個Issues(Issues
  3. 任何轉(zhuǎn)載請注明出處
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容