美文网首页Android知识积累
EffectiveAndroidUI 概述

EffectiveAndroidUI 概述

作者: 北疆_ | 来源:发表于2016-04-05 07:42 被阅读877次

    邂逅

    Android-CleanArchitecture 推荐,看到了这个略吊的项目名称EffectiveAndroidUI,3000+start果断把源码看遍。Android-CleanArchitecture 博文是Android初级架构的经典文章,建议有性趣的同学要看一下。

    观后感

    • 项目使用不是dagger2,而是用的是square的dagger略显过时;
    • EffectiveAndroidUI 就是标题党,实践上是对ViewHolder抽象化,使用工厂(AdapterFactory)类来减小Adapter和ListUI界面的相互依赖关系。
      优点:使Adapter相对的独立,抽离ViewHolder中的事件处理,配合Presenter,易于维护,代码脉络相对清晰。
      缺点:较大的增加了代码的复杂度,建议项目初期不要使用,在项目进行架构优化是可以考虑引入。
    • 使用DraggablePanel 实现YouTube的视频拖拽浮动的功能,感觉略吊。
    • 像Android-CleanArchitecture使用了Navigator类来统一处理界面之间的导航关系
    • Renderers 从项目提取的开源库 减少Adapter 和 List之间的耦合 ;

    代码走读

    项目使用三种布局来分别适配了低版本(v10),常用版本(v11+), 及平板的布局。


    这个很重要,因为俺就被这搞糊涂了,一开始跟着v11入口看代码,快看完的时候发现MainActivity.java 有一个Fragment的初始化
    private void initializeTvShowFragment() {
            tvShowFragment = (TvShowFragment) getSupportFragmentManager().findFragmentById(R.id.f_tv_show);
        }
    

    然后就,有点懵了....


    现在开始从V11开始


    MVP
    TvShowCatalogFragment/TvShowDraggableFragment使用的是MVP模式,一句话概括就是:

    明确(定义接口)UI界面的功能,把UI的交互逻辑放入Presenter实现。

    如果接触过一些老项目的同学应该会深有感悟,随着项目功能的增加Activity/Fragment越来越重,耦合越来越强,使代码复用变得很难,无法积累及实现模块化,敏捷的开发。
    故MVP就流行起来了,MVP还有一个好处就是方便Unit test。最新的Android Testing Support Library 也提倡使用MVP,在官方的Demo:android-testing也使用MVP,强烈建议同学们去看这个测试入门Demo。
    进阶阅读:MVVM wiki ,还有官网的Data Binding Guide , 过一边较好。

    重点代码举例
    抽离MVP,TvShowCatalogFragment只有AdapterFactory比较重要

      private void initializeGridView() {
        adapter = tvShowRendererAdapterFactory.getTvShowRendererAdapter(tvShows);
        gv_tv_shows.setAdapter(adapter);
      }
    

    TvShowRendererAdapterFactory.java

    public class TvShowRendererAdapterFactory {
    
      private final TvShowRendererBuilder rendererBuilder;
      private final LayoutInflater layoutInflater;
    
      @Inject
      public TvShowRendererAdapterFactory(TvShowRendererBuilder rendererBuilder,
          LayoutInflater layoutInflater) {
        this.rendererBuilder = rendererBuilder;
        this.layoutInflater = layoutInflater;
      }
    
      public RendererAdapter<TvShow> getTvShowRendererAdapter(final TvShowCollection tvShowCollection) {
        return new RendererAdapter<TvShow>(layoutInflater, rendererBuilder, tvShowCollection);
      }
    }
    

    整个项目名称是EffectiveAndroidUI其实略有点夸张,这里突然想起大学外面的小菜馆名字“重庆大饭店”,“某某洗脚城”.....。Effective的体现:

    EffectiveAndroid.jpg RendererBuilder

    核心是通过RendererAdapterFactory,T 数据泛华,RendererBuilder 来解强耦合

    动画简述

    动画实现的概述
    动画主要通过使用ViewDragHelper, 界面布局使用一个Activity叠加两个Fragment来实现。 可以点击ViewDragHelper 简单初始化案例

    DraggableView

    初始化

      @Override protected void onFinishInflate() {
        super.onFinishInflate();
        if (!isInEditMode()) {
          mapGUI(); //DragView ListView 初始化
          initializeTransformer(); // Transform 管理类的初始化化
          initializeViewDragHelper();
        }
      }
    

    重要方法的逻辑翻译

     private boolean smoothSlideTo(float slideOffset) {
        final int topBound = getPaddingTop();
        //(父控件参数 - dragView最小化参数) * 偏移因数 =  实践偏移量
        int x = (int) (slideOffset * (getWidth() - transformer.getMinWidthPlusMarginRight()));
        int y = (int) (topBound + slideOffset * getVerticalDragRange());
        if (viewDragHelper.smoothSlideViewTo(dragView, x, y)) {
          ViewCompat.postInvalidateOnAnimation(this);
          return true;
        }
        return false;
      }
    

    onTouchEvent

      @Override public boolean onTouchEvent(MotionEvent ev) {
        ...
        if (activePointerId == INVALID_POINTER) { //是否是无效的点,是不做操作
          return false;
        }
        viewDragHelper.processTouchEvent(ev); //把事件交给ViewDragHelper处理,处理完触发回调
        if (isClosed()) { //是否是已经关闭,可拖动的View不在屏幕显示。是不做操作
          return false;
        }
        //event X, Y 加上parentView的坐标偏移,是否在ChildView 中
        boolean isDragViewHit = isViewHit(dragView, (int) ev.getX(), (int) ev.getY());
        boolean isSecondViewHit = isViewHit(secondView, (int) ev.getX(), (int) ev.getY());
        //Down事件和Up事件X坐标的变化量,当变化量大于指定值最大或最小化dragView
        analyzeTouchToMaximizeIfNeeded(ev, isDragViewHit);
        if (isMaximized()) {
          dragView.dispatchTouchEvent(ev);
        } else {
          dragView.dispatchTouchEvent(cloneMotionEventWithAction(ev, MotionEvent.ACTION_CANCEL));
        }
        return isDragViewHit || isSecondViewHit;
      }
    

    clampViewPositionHorizontal

      @Override public int clampViewPositionHorizontal(View child, int left, int dx) {
        int newLeft = draggedView.getLeft();
        //当可以拖动的View最小化并且X轴的速度大于某个速度, 
        //或可以拖动的View在底部,但是没有靠右时更新left的值
        if ((draggableView.isMinimized() && Math.abs(dx) > MINIMUM_DX_FOR_HORIZONTAL_DRAG) || (
            draggableView.isDragViewAtBottom()
                && !draggableView.isDragViewAtRight())) {
          newLeft = left;
        }
        return newLeft;
      }
    

    clampViewPositionVertical

      @Override public int clampViewPositionVertical(View child, int top, int dy) {
        int newTop = draggableView.getHeight() - draggableView.getDraggedViewHeightPlusMarginTop(); 
        //当可以拖动的View最小化并且Y轴的速度大于某个速度, 
        //或可以拖动的View在底部,但是没有靠右时更新Top的值
        if (draggableView.isMinimized() && Math.abs(dy) >= MINIMUM_DY_FOR_VERTICAL_DRAG
            || (!draggableView.isMinimized() && !draggableView.isDragViewAtBottom())) {
    
          final int topBound = draggableView.getPaddingTop();
          final int bottomBound = draggableView.getHeight()
              - draggableView.getDraggedViewHeightPlusMarginTop()
              - draggedView.getPaddingBottom();
        // bottomBound <= top <= topBound
          newTop = Math.min(Math.max(top, topBound), bottomBound);
        }
         return newTop;
      }
    

    onViewPositionChanged change scale/alpha/position

    triggerOnReleaseActionsWhileVerticalDrag

      private void triggerOnReleaseActionsWhileVerticalDrag(float yVel) {
        if (yVel < 0 && yVel <= -Y_MIN_VELOCITY) { //Y速度向上
          draggableView.maximize();
        } else if (yVel > 0 && yVel >= Y_MIN_VELOCITY) {//Y速度向向下
          draggableView.minimize();
        } else {
          if (draggableView.isDragViewAboveTheMiddle()) { //y轴的拖动范围大于一半时
            draggableView.maximize();
          } else {
            draggableView.minimize();
          }
        }
      }
    

    相关文章

      网友评论

        本文标题:EffectiveAndroidUI 概述

        本文链接:https://www.haomeiwen.com/subject/eziulttx.html