Android动态片段加载进度条的可见性不会设置

时间:2016-12-14 13:38:27

标签: android android-layout android-fragments

我正在使用Android片段加载我的应用程序中的代码。要创建一个简单的加载器,我有LoadingFragment extends Fragment,然后我的片段类扩展了它,例如:MyFragment extends LoadingFragment

LoadingFragmenthideLoadershowLoader理论上我的子类Fragment应该能够在onCreateViewonPostExecute中调用以显示和隐藏进度条在负载之间。

布局明智我有一个main_layout.xml,其中包含动态片段的framelayout和一个包含进度条的静态relativelayout。

目前我的片段加载并从另一个内部替换点击元素,但我删除了该代码。

问题

问题是setVisibilty中的LoadingFragment在从子类调用时似乎没有效果,例如MyFragment,为什么会这样?

我已经LoadingFragment View我自己的viewMaster main_layout变量,我认为应该引用public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); MyFragment myFragment = MyFragment.newInstance(); getSupportFragmentManager().beginTransaction() .replace(R.id.fragment_holder, myFragment).commit(); } } 但仍然可见性变化似乎无效?

MainActivity

public class LoadingFragment extends Fragment {

    View viewMaster;

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

        viewMaster = inflater.inflate(R.layout.main_layout, container, false);

        return viewMaster;
    }

    public void showLoader() {

        viewMaster.findViewById(R.id.fragment_holder).setVisibility(View.INVISIBLE);
        viewMaster.findViewById(R.id.loading).setVisibility(View.VISIBLE);
    }

    public void hideLoader() {

        viewMaster.findViewById(R.id.fragment_holder).setVisibility(View.VISIBLE);
        viewMaster.findViewById(R.id.loading).setVisibility(View.INVISIBLE);
    }
}

LoadingFragment

public class MyFragment extends LoadingFragment {

    View view;

    public MyFragment() {}

    public static MyFragment newInstance() {
        MyFragment fragment = new MyFragment();
        return fragment;
    }

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

        super.onCreateView(inflater, container, savedInstanceState);
        super.showLoader();

        view = inflater.inflate(R.layout.fragment_lans, container, false);

        MyFragment.ApiCallJob apicalljob = new MyFragment.ApiCallJob();
        apicalljob.execute("a string");

        return view;
    }

    public class ApiCallJob extends AsyncTask<String, Void, String> {

        @Override
        protected String doInBackground(String[] params) {
            // do things
        }

        @Override
        protected void onPostExecute(String data) {
            // do things
            // tried both to be sure but they should do the same?  
            hideLoader();
            MyFragment.super.hideLoader();
        }
    }

}

MyFragment

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="app.stats.MainActivity"
    android:orientation="horizontal">

    <FrameLayout
        android:id="@+id/fragment_holder"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    </FrameLayout>

    <RelativeLayout
        android:id="@+id/loading"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">

        <ProgressBar
            style="?android:attr/progressBarStyleLarge"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:id="@+id/progress_bar"/>
    </RelativeLayout>

</RelativeLayout>

main_layout.xml

ReportDocument report = new ReportDocument();

3 个答案:

答案 0 :(得分:9)

  

问题是setVisibility中的LoadingFragment在从子类调用时似乎没有效果,例如MyFragment,为什么会这样?

让我们看一下调用MyFragment onCreateView时会发生什么:

您拨打super中的onCreateView LoadingFragment。这会使main_layout膨胀并返回膨胀的视图。请注意,此视图未在MyFragment 中引用(即View mainLayout = super.onCreateView(inflater, container, savedInstanceState);

您刚刚对包含loading视图组的视图进行了充气,​​然后将其丢弃。但是,您确实设法在LoadingFragment超类中保存对该视图的引用。

接下来你膨胀R.layout.fragment_lans并且(在开始加载之后)将那个视图作为要在片段中使用的视图返回。

所以要注意的是LoadingFragment现在引用了一个在片段的活动视图层次结构中没有的视图。

鉴于此,毫无疑问setVisibility没有做任何事情,因为片段没有显示该视图。

我不会使用继承来执行此操作,但如果您必须使用它,那么这里是如何解决您的问题。

  1. 我们只使用没有视图组包装器的ProgressBar。因为它在RelativeLayout,所以让它居中。然后将其设为android:visibility="gone",使其实际上脱离片段布局:

            <ProgressBar
                android:id="@+id/progress_bar"
                style="?android:attr/progressBarStyleLarge"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerInParent="true"
                android:visibility="gone"/>
    

    您将把这个进度条放在每个LoadingFragment子类的布局中,包括fragment_lans.xml。您可以使用<include>标记来简化生活。

  2. 更改LoadingFragment以便a)它不会干扰其子类布局的膨胀,并且b)它使用子类'活动视图层次结构中的进度条:

    public class LoadingFragment extends Fragment {
    
        public void showLoader() {
    
            if (getView() != null) {
               View progressBar = getView().findViewById(R.id.progress_bar);
               if (progressBar != null) {
                   progressBar.setVisibility(View.VISIBLE);
               }
            }
        }
    
        public void hideLoader() {
    
            if (getView() != null) {
               View progressBar = getView().findViewById(R.id.progress_bar);
               if (progressBar != null) {
                   progressBar.setVisibility(View.GONE);
               }
            }
        }
    }
    
  3. 现在你应该看到你的期望了。

    修改

    如果确实想要使用您开始使用的布局方案,这是我的建议:

    您的活动正在膨胀具有进度条的main_layout,因此我会对该活动承担部分责任。

    现在,您可以为片段编写一些代码,这些代码将遍历视图层次结构并查找进度条。那不是我的偏好。

    这是另一种方法:

    • 创建界面

      interface ProgressDisplay {
      
          public void showProgress();
      
          public void hideProgress();
      }
      
    • 让活动实现它

          public class MainActivity extends AppCompatActivity implements ProgressDisplay {
      

      ...

          public void showProgress() {
              findViewById(R.id.loading).setVisibility(View.VISIBLE);
          }
      
          public void hideProgress() {
              findViewById(R.id.loading).setVisibility(View.GONE);
          }
      
    • 然后将方法添加到调用活动的LoadingFragment

          protected void showProgress() {
              if (getActivity() instanceof ProgressDisplay) {
                  ((ProgressDisplay) getActivity()).showProgress();
              }
          }
      
          protected void hideProgress() {
              if (getActivity() instanceof ProgressDisplay) {
                  ((ProgressDisplay) getActivity()).hideProgress();
              }
          }
      

    通过这种方式,您可以使用进度视图执行任何夸大布局的活动,并让它实现ProgressDisplay,以便您可以使用LoadingFragment类。

    你也可以创建一个LoadingActivity类和子类。

答案 1 :(得分:2)

您通过View上的showLoader调用setVisibility,因为您将其他视图作为片段视图返回,因此不会用于在屏幕上绘制。

这样的事情应该有效(MyFragment):

<!DOCTYPE html>
<html lang="en" class="no-js">

  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    
    <link href="http://fonts.googleapis.com/css?family=Open+Sans:400,300,700" rel="stylesheet" type="text/css" />
    <link rel="stylesheet" href="style.css" />
    <!-- Resource style -->
    <script src="js/modernizr.js"></script>
    <!-- Modernizr -->
    <title>Switch......</title>
  </head>

  <body>
    <main id="barba-wrapper">
      <div class="cd-index barba-container">
        <div>
          <h1>Animated Page Transition</h1>
          <a class="cd-btn" href="about.html" data-type="page-transition"><svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="200px" height="1.49468in" version="1.1" style="shape-rendering:geometricPrecision; text-rendering:geometricPrecision; image-rendering:optimizeQuality; fill-rule:evenodd; clip-rule:evenodd"
viewBox="0 0 4386 1167"
 xmlns:xlink="http://www.w3.org/1999/xlink">
 <defs>
  <style type="text/css">
   <![CDATA[
    .fil0 {fill:#FFCC29}
   ]]>
  </style>
 </defs>
 <g id="Layer_x0020_1">
  <metadata id="CorelCorpID_0Corel-Layer"/>
  <path class="fil0" d="M583 0l3219 0c321,0 584,262 584,583l0 0c0,321 -263,584 -584,584l-3219 0c-321,0 -583,-263 -583,-584l0 0c0,-321 262,-583 583,-583zm1198 262c-39,-44 -111,-74 -198,-74 -156,0 -264,112 -264,259 0,105 63,158 129,196 57,33 81,63 81,105 0,57 -48,92 -95,92 -47,0 -91,-22 -120,-56l-98 124c43,47 125,82 219,82 135,0 264,-86 264,-262 0,-111 -78,-168 -136,-203 -51,-30 -75,-51 -75,-93 0,-65 54,-96 93,-96 39,0 77,17 102,46l98 -120zm729 148l-158 0 -126 367 -2 0 -5 -367 -133 0 -136 367 -2 0 6 -367 -157 0 20 561 157 0 139 -346 1 0 7 346 163 0 226 -561zm230 0l-158 0 -97 561 158 0 97 -561zm35 -170c0,-47 -29,-81 -81,-81 -55,0 -94,49 -94,104 0,42 28,80 78,80 55,0 97,-46 97,-103zm348 170l-95 0 25 -137 -153 0 -23 137 -74 0 -22 126 74 0 -47 270c-3,17 -5,35 -5,48 0,79 47,127 141,127 27,0 61,-8 82,-18l20 -119c-10,3 -26,6 -38,6 -31,0 -46,-16 -46,-47 0,-9 2,-25 4,-37l42 -230 91 0 24 -126zm390 26c-25,-23 -61,-43 -130,-43 -169,0 -270,193 -270,373 0,124 56,222 189,222 53,0 99,-16 129,-41l-41 -124c-17,12 -34,21 -57,21 -46,0 -66,-36 -66,-96 0,-91 42,-212 112,-212 27,0 41,10 53,23l81 -123zm478 93c0,-64 -32,-136 -123,-136 -69,0 -114,43 -144,94l-2 0 59 -332 -157 0 -142 816 157 0 57 -329c11,-65 45,-110 88,-110 34,0 44,25 44,55 0,13 -2,27 -4,40l-61 344 158 0 59 -344c7,-35 11,-71 11,-98l0 0zm-3350 442c220,0 398,-178 398,-398 0,-220 -178,-398 -398,-398 -220,0 -398,178 -398,398 0,220 178,398 398,398zm-80 -387l79 -330 142 34 -80 330 -141 -34zm139 189c14,-58 -22,-115 -79,-129 -57,-14 -115,21 -129,79 -14,57 22,115 79,128 57,14 115,-21 129,-78z"/>
 </g>
</svg>
</a>
        </div>
      </div>
    </main>
    <div class="cd-cover-layer"></div>
    <div class="cd-loading-bar"></div>
    
    <script data-require="jquery@3.0.0" data-semver="3.0.0" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.0.0/jquery.js"></script>
    <script src="app.js"></script>
    <!-- Resource jQuery -->
  </body>

</html>

答案 2 :(得分:0)

如果您正在使用继承,则无法将布局分配给父片段。

您可以利用像这样的butterknife的View Binding继承,并编写更干净的代码。

   import android.graphics.Color;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v7.widget.Toolbar;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ProgressBar;

import com.emerson.techdayapp.R;
import com.emerson.techdayapp.view.activity.MainActivity ;

import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.Unbinder;

/**
 * Base fragment created to be extended by every fragment in this application. This class provides
 * dependency injection configuration, ButterKnife Android library configuration and some methods
 * common to every fragment.
 */
public abstract class BaseFragment extends Fragment {

    private Unbinder unbinder;

    @BindView(R.id.htab_toolbar)
    Toolbar mToolbar;
    @BindView(R.id.loading_view)
    ProgressBar loadingView;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        return inflater.inflate(getFragmentLayout(), container, false);
    }

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

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

        //bind view
        injectViews(view);

        //set page title
        setUpToolBar(getPageTitle());

        //add click listeners
        setUpViewEvents();

        //make service call
        fillData();
    }

    /**
     * @return resource if of fragment layout
     */
    protected abstract int getFragmentLayout();

    /**
     * Set toolbar title
     *
     * @return
     */
    protected abstract String getPageTitle();

    /**
     * Add click listeners
     */
    protected abstract void setUpViewEvents();

    /**
     * Make Web serve calls here
     */
    protected abstract void fillData();


    /**
     * Inject View
     *
     * @param view
     */
    private void injectViews(final View view) {
        unbinder = ButterKnife.bind(this, view);
    }


    /**
     * Set up toolbar
     *
     * @param pageTitle
     */
    private void setUpToolBar(String pageTitle) {

        getActivity().setTitle(pageTitle);

        if (mToolbar != null) {
            ((MainActivity ) getActivity()).setSupportActionBar(mToolbar);

            ((MainActivity ) getActivity()).getSupportActionBar()
                    .setDisplayHomeAsUpEnabled(true);

            mToolbar.setNavigationIcon(R.drawable.ic_drawer);

            mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {

                    //TODO what to do on back press
                }
            });

            mToolbar.setTitleTextColor(Color.WHITE);
        }
    }

    public void showProgressDialog() {
        if (null != loadingView)
            loadingView.setVisibility(View.VISIBLE);
    }

    public void dismissProgressDialog() {

        if (null != loadingView)
            loadingView.setVisibility(View.GONE);
    }


    @Override
    public void onDestroyView() {
        super.onDestroyView();
        unbinder.unbind();
    }
}

然后使用像这样的基础片段

public class MyFragment extends BaseFragment {

    public MyFragment() {
    }

    public static MyFragment newInstance() {
        MyFragment fragment = new MyFragment();
        return fragment;
    }

    @Override
    protected int getFragmentLayout() {

        //put your frag layout id here
        return R.layout.frag_pulse;
    }

    @Override
    protected String getPageTitle() {

        //Add some title to page
        return "Some Title";
    }

    @Override
    protected void setUpViewEvents() {

    }

    @Override
    protected void fillData() {

        new AsyncTask<String, Void, String>() {

            @Override
            protected void onPreExecute() {
                super.onPreExecute();

                //Show Progress
                showProgressDialog();
            }

            @Override
            protected String doInBackground(String... strings) {

                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                return null;
            }

            @Override
            protected void onPostExecute(String s) {
                super.onPostExecute(s);

                //Hide Progress
                dismissProgressDialog();
            }
        };

    }
} 

此处需要注意的是,您的片段布局必须包含一个工具栏ID htab_toolbar和一个ID为loading_view的进度条,因为它由基类使用