精华内容
下载资源
问答
  • 我有ViewGroup.addView()方法的问题.我使用此代码为我的布局添加新视图:TalbeLayout parent = (TableLayout)findViewById(R.id.this_does_not_matter);parent.removeAllViews(); //this view group contains ...

    我有ViewGroup.addView()方法的问题.我使用此代码为我的布局添加新视图:

    TalbeLayout parent = (TableLayout)findViewById(R.id.this_does_not_matter);

    parent.removeAllViews(); //this view group contains something at start

    TextView tv = new TextView(this);

    tv.setText("some text");

    TableLayout.LayoutParams lp = new TableLayout.LayoutParams(TableLayout.LayoutParams.MATCH_PARENT, TableLayout.LayoutParams.WRAP_CONTENT);

    tv.setLayoutParams(lp);

    parent.addView(tv);

    之后,我无法看到我的TextView.更重要的是,parent.getChildCount()返回正确的值(如果我尝试添加一个子节点,则返回1).在父视图的onClick()方法中,我尝试获取TextView的宽度和高度,所有这些都等于0.为TableView调用requestLayout(),invalidate()和measure(500,50)并且没有效果.我甚至尝试在view.post(Runnable)的帮助下添加新视图,尽管此代码在UI线程中执行.

    我很困惑.我真的不明白会发生什么.有人可以解释一下我做错了什么吗?

    一个有趣的时刻:

    setLayoutParams()无效.如果我设置宽度= 500和高度= 50的参数,在onClick方法中我得到宽度= -1和高度= -1的参数.

    TableRow添加后的代码:

    TableLayout parent = (TalleLayout)findViewById(R.id.this_does_not_matter);

    parent.removeAllViews(); //this view group contains something at start

    TextView tv = new TextView(this);

    tv.setText("some text");

    TableLayout.LayoutParams lp = new TableLayout.LayoutParams(500, 50);

    TableRow.LayoutParams tlp = new TableRow.LayoutParams(500, 50);

    TableRow tr = new TableRow(this);

    tr.addView(tv, tlp);

    parent.addView(tr, lp);

    parent.invalidate();

    parent.requestLayout();

    我发现了一件有趣的事情.此活动从TabHost运行.只有在此TabHost中首次选择“活动”时,才会显示“addView bug”.如果我第一次从另一个标签启动Activity,一切正常.

    解决方法:

    我找到了解决方案如果关闭布局动画与android:animateLayoutChanges =“false”一切正常.但我仍然不知道为什么会这样.如果有人知道这种行为的原因,那对我来说很有趣.

    标签:android,ui-thread

    来源: https://codeday.me/bug/20190708/1405308.html

    展开全文
  • 该楼层疑似违规已被系统折叠隐藏此楼查看此楼RT,LZ在做一个从传感器采集数据后通过aChartEngine绘图表的...然后更新UI,也就是在处理方法中addView,但是怎么都显示不出来,好奇的是,放到UI主线程中也不行,添加...

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼

    RT,LZ在做一个从传感器采集数据后通过aChartEngine绘图表的应用程序,但是在绘图时遇到点问题,我在布局文件中有两个LinearLayout,赋过了id,在UI主线程中通过handler的handmessage方法接受子线程发来的msg,然后更新UI,也就是在处理方法中addView,但是怎么都显示不出来,好奇的是,放到UI主线程中也不行,添加View的代码我放在了onRensume中(提示放在handler中也试过,但是都没有反应),相关代码如下:

    //监听子线程事件

    handler = new Handler() {

    @SuppressWarnings("deprecation")

    @Override

    public void handleMessage(Message msg) {

    // TODO Auto-generated method stub

    if(msg.what==0x0001) {

    adcSetChannel(1);

    adcSetResol(12);

    double temp = InterData.temp;

    mTemp.setText(getResources()

    .getString(R.string.con2)+new DecimalFormat("#.###").format(temp)+"摄氏度");

    double x = 0;

    double y = 0;

    Calendar c = Calendar.getInstance();

    x = c.get(Calendar.SECOND);

    y = temp;

    mTempDataset.getSeriesAt(0).add(x, y);

    mTempView.repaint();

    }

    else if(msg.what==0x0002) {

    double adValue = (float)adcReadValue()*3.3/4096;

    //更新显示的ADC转换的值

    mGas.setText(getResources()

    .getString(R.string.con1)+new DecimalFormat("#.###")

    .format(adValue)+"V");

    double x = 0;

    double y = 0;

    Calendar c = Calendar.getInstance();

    x = c.get(Calendar.SECOND);

    y = adValue;

    mGasDataset.getSeriesAt(0).add(x, y);

    mGasView.repaint();

    }

    }

    };

    展开全文
  • IBinder 对象 //也就是说 Android Framework与WMS之间是通过Binder机制进行通信 sWindowManagerService = IWindowManager.Stub.asInterface(ServiceManager.getService("window")); } return sWindowManagerService;...

             上一节 描述了一个xml 通过LayoutInflactor 变成了一颗view树,并且存储在ViewGroup的mChildren数组里,被添加到PhoneWindow的mDecorView成员里的过程。最后是跟到handleResumeActivity,mDecorView 在handleResumeActivity里被设置给WindowManager,那么WindowManager拿着mDecorView,传递给了谁,怎么显示到界面上的呢。

            复习一下ActivityThread.handleResumeActivity() ,就开始分析WindowManager。 

    public final class ActivityThread extends ClientTransactionHandler {
        final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward,
                                        boolean reallyResume) {
                ……
                final Activity a = r.activity;
                    // 1.获取WindowManager
                    ViewManager wm = a.getWindowManager();
                    a.mDecor = decor;
                    if (a.mVisibleFromClient) {
                        a.mWindowAdded = true;
                        // 2.将DecorView添加到窗口中
                        wm.addView(decor, l);
                    }
                }
                if (!r.activity.mFinished && willBeVisible
                        && r.activity.mDecor != null && !r.hideForNow) {
                    // 代码省略
                    if (r.activity.mVisibleFromClient) {
                        // 3.使得Activity变得可见,其实是设置DecorView变为可见
                        r.activity.makeVisible();
                    }
                }
                    // 4.最后通知ActivityManagerNative,该Activity己经变为resume状态
                    ActivityManagerNative.getDefault().activityResumed(token);
            }
        }
    }

             我们看到标注1 的地方,PhoneWindow的DecorView时通过WindowManager.addView()添加给 WindowManager 的,WindowManager 在 Java 层的具体实现是WindowManagerImpl,

    public final class WindowManagerImpl implements WindowManager {
        private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
        // Window对象
        private final Window mParentWindow;
        private WindowManagerImpl(Display display, Window parentWindow) {
            mDisplay = display;
            mParentWindow = parentWindow;
        }
        @Override
        public void addView(View view, ViewGroup.LayoutParams params) {
            mGlobal.addView(view, params, mDisplay, mParentWindow);
        }
    
    }

            WindowManagerImpl的addview实现其实调用的是WindowManagerGlobal这个类。添加View、移除View、更新View的布局等具体的工作都交给了WindowManagerGlobal这个类,WindowManagerGlobal的addView方法:

    public final class WindowManagerGlobal {
        private final ArrayList<View> mViews = new ArrayList<View>();
        private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();
        // 将View添加到WindowManager中,也就是在手机窗口中显示该View
        public void addView(View view, ViewGroup.LayoutParams params,
                            Display display, Window parentWindow) {
            // 检查参数有效性等代码省略
            final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
            ViewRootImpl root;
            View panelParentView = null;
            synchronized (mLock) {
                // ……
                // 1.构建ViewRootImpl
                root = new ViewRootImpl(view.getContext(), display);
                view.setLayoutParams(wparams);
                mViews.add(view);
                mRoots.add(root);
                mParams.add(wparams);
            }
            try {
                // 2.调用ViewRootImpl的setView方法将View显示到手机窗口中
                root.setView(view, wparams, panelParentView);
            } catch (RuntimeException e) {
            }
        }
    }

            看标注1的地方!终于看到非常重要的ViewRootImpl 了!ViewRootImpl在View的绘制发挥重要的作用,所有View的绘制以及事件分发等交互都是通过它来执行或传递的。ViewRootImpl管理Window中所有的View,每个Activity中ViewRootImpl的数量取决于这里的mWindowManager.addView的调用次数。

           从WindowManagerGlobal名称可以看出,它是一个全局的WindowManager,其内部维护了一个View的List ,存放了当前的View(一路从PhoneWindow传过来的mDecorView )。在 WindowManagerGlobal  的addView()里, 主要就是去构建ViewRootImpl ,把view添加进List,然后调用ViewRootImpl的setView方法,这篇笔记剩下的内容都是围绕这个setView()的过程展开的。

    public final class ViewRootImpl implements ViewParent, View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks {
        public final Context mContext;
        public final Surface mSurface = new Surface();
        public ViewRootImpl(Context context, Display display) {
            mContext = context;
            // 获取Window Session, 也就是与WindowManagerService建立连接
            mWindowSession = WindowManagerGlobal.getWindowSession();
            final IWindowSession mWindowSession;
        }
        public void setView(View view, WindowManager.LayoutParams attrs,
                            View panelParentView) {
            synchronized (this) {
                // 1.请求布局
                requestLayout();
                try {
                    // 2.向WMS发起请求
                   res = mWindowSession.addToDisplayAsUser(mWindow, mSeq, mWindowAttributes,
                                  getHostVisibility(), mDisplay.getDisplayId(), userId, mTmpFrame,
                                  mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                                  mAttachInfo.mDisplayCutout, inputChannel,
                                  mTempInsets, mTempControls);
                          setFrame(mTmpFrame);
                }
            }
    }

              ViewRootImpl的setView() 里出现了一个新的类:WindowSession 。这显然是一次通信,我们先中断一下对setView的跟踪,研究一下谁和谁通信,怎么通信。

            我们看到,直到ViewRootImpl的setView方法,程序还跑在APP端的UI线程,而WindowManagerService是运行在另一个的进程的,和APP享有不同的内存空间,APP和WMS的跨进程通信是怎么进行的呢?就是靠WindowSession了,WindowSession是在创建ViewRoot时,通过WindowManagerGlobal.getWindowSession()方法获取的 :
            mWindowSession = WindowManagerGlobal.getWindowSession();

    class WindowManagerGlobal{
        private static IWindowSession sWindowSession;
        public static IWindowSession getWindowSession() {
            synchronized (WindowManagerGlobal.class) {
                if (sWindowSession == null) {
                    try {
                        InputMethodManager imm = InputMethodManager.getInstance();
                        // 1.获取WindowManagerService
                        IWindowManager windowManager = getWindowManagerService();
                        // 2.与WindowManagerSerice建立—个Session
                        //    Framework层与Native层建立通信,
                        //    双方有什么需求都通过这个Session来交换信息
                        sWindowSession = windowManager.openSession(
                        imm.getClient(), imm.getInputContext());
                    } 
                }
                return sWindowSession;
            }
        }
        // 3.获取WindowManagerService
        public static IWindowManager getWindowManagerService() {
            synchronized (WindowManagerGlobal.class) {
                if (sWindowManagerService == null) {
                // 4.ServiceManager.getService返回的是 IBinder 对象
                //也就是说 Android Framework与WMS之间是通过Binder机制进行通信
                sWindowManagerService = IWindowManager.Stub.asInterface(ServiceManager.getService("window"));
            }
            return sWindowManagerService;
           }
        }
    }

            这段代码出现了两个新的对象:IWindowManager和 IWindowSession

    •         IWindowManager:WMS 继承了IWindowManager.Stub,是一个binder,对外提供了IWindowManager,供跨进程调用;
    •         Session 继承自 IWindowSession.Stub,同样是一个binder,对外提供IWindowSession,供跨进程调用;

             建立连接的过程大概是这样的:(看WindowManagerGlobal的静态方法getWindowManagerService())WindowManger向WMS发送一个建立连接的Binder进程间通信请求。WMS服务接收到这个请求之后,就会在内部为这个应用保留一个单独的Session,这是一个类型为Session的Binder本地对象,WMS将这个Binder返回给应用程序进程,当App需要通信时,调用Binder的openSession()就会得到一个Session代理对象。

            具体来说,在创建ViewRootImpl时,ViewRootImpl通过请求WMS获取到了这个Session代理对象,保存在自己的成员变量mWindowSession中。拥有了mWindowSession的ViewRootImpl 因此可以成为  Framework 层与 Native 层(WMS是运行在Native层的)的通信桥梁。ViewRootImpl和WMS的通信是双向的,不仅仅是ViewRootImpl.setView()过程发生APP和WMS的通信,WMS向ViewRootImpl传递touch事件也是通过mWindowSession完成间接的通信。

             这里可以对比一下AMS与应用进程的IPC

            ActivityManager类内部调用ActivityManagerNative的getDefault函数得到一个ActivityManagerProxy对象,AMS继承ActivityManagerNative,通过它可与AMS通信。所以说,ActivityManagerProxy 是AMS在客户端进程的一个代理,通过AMP里面的方法请求AMS。那么客户端进程在AMS的代理呢?这个代理就是ApplicationThreadProxy,如果AMS要通知Activity,那么就是使用ApplicationThreadProxy。描述参考

            好了,知道ViewRootImpl 时怎么完成和WMS的跨进程通信之后,说回本文的ViewRootImpl.setView(),上文已经跟到这段代码:

    public class ViewRootImpl   
       
        public void setView(View view, WindowManager.LayoutParams attrs,
                            View panelParentView) {
            synchronized (this) {
                // 1.请求布局
                requestLayout();
                try {
                    // 2.向WMS发起请求
                   res = mWindowSession.addToDisplayAsUser(mWindow, mSeq, mWindowAttributes,
                                  getHostVisibility(), mDisplay.getDisplayId(), userId, mTmpFrame,
                                  mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                                  mAttachInfo.mDisplayCutout, inputChannel,
                                  mTempInsets, mTempControls);
                          setFrame(mTmpFrame);
                }
            }
        }
    }

           ViewRootImpl.setView()把View和ViewRootImpl关联了起来,过程很复杂,我们主要关注这两件事

    •  requestLayout() 是用来整个视图树的绘制操作,执行我们熟悉的 measure > layout > draw 的过程。performDraw() 内容绘制等另开一篇讲。
    • mWindowSession.addToDisplayAsUser(),这就是之前分析的通过这个sWindowSession间接与WMS通信的过程

            sWindowSession.addToDisplay() 调用到远端Session对象的addToDisplay方法。远端Session对象收到这个请求后,转接给WMS。如此一来显示Dialog或者Activity中的mDecorView请求就交给了WMS去处理了。

           WMS 到底由哪些能力 最后,可以从IWindowSession接口的看出——

    /**
     * System private per-application interface to the window manager.
     */
    interface IWindowSession {
        int addToDisplay(IWindow window, int seq, in WindowManager.LayoutParams attrs, in int viewVisibility, in int layerStackId, out Rect outFrame, out Rect outContentInsets,
                         out Rect outStableInsets, out DisplayCutout.ParcelableWrapper displayCutout, out InputChannel outInputChannel, out InsetsState insetsState, out InsetsSourceControl[] activeControls);
        int addToDisplayAsUser(……);
        void remove(IWindow window);
        //更改窗口的参数。根据新参数返回屏幕上窗口的新框架(不包含位置信息)和窗口的Surface。
        //如果窗口不可见,则Surface将无效,否则可以使用它绘制窗口的内容。
        int relayout(IWindow window, int seq, in WindowManager.LayoutParams attrs,
                     int requestedWidth, int requestedHeight, int viewVisibility,
                     int flags, long frameNumber, out Rect outFrame,
                     out Rect outContentInsets, out Rect outVisibleInsets, out Rect outStableInsets,
                     out Rect outBackdropFrame,
                     out DisplayCutout.ParcelableWrapper displayCutout,
                     out MergedConfiguration outMergedConfiguration, out SurfaceControl outSurfaceControl,
                     out InsetsState insetsState, out InsetsSourceControl[] activeControls,
                     out Point outSurfaceSize, out SurfaceControl outBlastSurfaceControl);
    
        boolean outOfMemory(IWindow window);
        ……
    }

            分析这个接口的方法,这些接口都没有和View有关的信息,而是以IWindow为单位操作,可以大致感受到,WMS的能力在于窗口的添加、移除、调整顺序等,图像的绘制与合成之类的不在WMS的能力范围内

            另外,有一种说法说“WMS其实管理的并不是Window,而是View”,也是对的,虽然类的注释里写的是 "to the window manager",窗口管理,但是WMS管理的其实是当前状态下哪个View应该在最上层显示,是这些View的z-order。也就是说,WMS管理的其实也不是WIndow,是属于某个Window下的View。

           好了,到这里,我们知道了我们可以通过ViewRootImpl的 WindowSession,把一个view给到WMS。WMS 会收到很多的view并决定哪一个在最上层显示,真正完成图像绘制的是APP端,而完成图层合成的是SurfaceFlinger服务。谁在真正绘制这些view,SurfaceFlinger怎么工作,我们应该给WMS 一个怎么样的view, 需要从我们前面那跳过的 requestLayout() 入手去跟,会再开一篇讲。

    总结

    • ActivityThread的 handleResumeActivity处,回去获取activity内部的WindowManager,是个全局单例。并且把PhoneWindow的decorView传递给 WindowManagerGlobal.
    • WindowManagerGlobal 内部维护了一个ViewRootImpl list,每次addView()时会创建时会创建一个ViewRootImpl。ViewRootImpl负责DecorView的测量布局绘制的调用,也负责从WMS获取TouchEvent事件后分发。
    • ViewRootImpl 拥有mWindowSession,实现了ViewRootImpl和WMS的跨进程通信,这是一种基于Binder的跨进程通信。ViewRootImpl通过sWindowSession向WMS发起显示Dialog或者Activity中的mDecorView请求,sWindowSession.addToDisplay方法调用到远端Session对象的addToDisplay方法。远端Session对象收到这个请求后,转接给WMS。如此一来添加请求就交给了WMS去处理了

    ---------------------------------------------------------------------------------------------------------------------------------

     AndroidUI渲染专题其他内容: 

            (一)LayoutInflactor和PhoneWindow 

            (二)WindowManager和ViewRootImpl

            (三)surface

    展开全文
  • 但是如果项目的设计架构本身就是 MVC 这样我们还可以用其他的一些方法来分解我们 Activity 和 Fragment 中的代码冗余,对,就像标题中说的,利用 ViewGroup 中的 addView 方法来实现 接下来我们就来演示一下具体是...

    转载自:https://blog.csdn.net/qdjdeveloper/article/details/82794727

    在日常开发中 我们会涉及到很多架构 例如 MVC  MVP MVVM 等等,如果我们的项目本身就是用 MVP 或 MVVM 架构, 那么 Activity 和 Fragment 中的代码冗余可能会相对小一些 但是如果项目的设计架构本身就是 MVC 这样我们还可以用其他的一些方法来分解我们 Activity 和 Fragment 中的代码冗余,对,就像标题中说的,利用 ViewGroup 中的 addView 方法来实现 接下来我们就来演示一下具体是如何来做到的,其实非常简单。

    这里我们新建一个工程来演示 工程名就为 AddView 吧!!!

    先上一张图来看看我们要做的东西:

     

    就是上面的界面  大家看到这里觉得这也太简单了 别着急 慢慢再往下看,这里的是比较简单,但这里只是用来做思想演示,道理大家明白就可以,下面我们来实现

    首先我们来创建一个 BaseCardView 代码如下:

    public abstract class BaseCardView {
        
        private Context mContext;
        private View mView;
        
        /**
         * 创建 card 不添加到 rootView 中
         *
         * @param root 需要添加的 rootView,不可以为空
         */
    
        public BaseCardView(Context context, @NonNull ViewGroup root) {
            this(context, root, false);
        }
    
        /**
         * 创建 card
         *
         * @param root 需要添加的 rootView,不可以为空
         * @param attachToRoot 是否添加到 rootView
         */
        public BaseCardView(Context context, @NonNull ViewGroup root, boolean attachToRoot) {
            mContext = context;
            createView(context, root, attachToRoot);
        }
    
    
        private void createView(Context context, ViewGroup root, boolean attachToRoot) {
            mView = LayoutInflater.from(context).inflate(onBindLayoutId(), root, attachToRoot);
            onViewCreated(mView);
        }
        
        protected abstract int onBindLayoutId();
    
        protected abstract void onViewCreated(View view);
    
        public View getView() {
            return mView;
        }
        
        protected Context getContext() {
            return mContext;
        }
    }

    接下来我们来实现我们看到的 3 个按钮

    第一个:HeaderCardView:

    public class HeaderCardView extends BaseCardView {
        
        public HeaderCardView(Context context, @NonNull ViewGroup root) {
            super(context, root);
        }
    
        @Override
        protected int onBindLayoutId() {
            return R.layout.header_card_view;
        }
    
        @Override
        protected void onViewCreated(View view) {
        }
    }

    看到这里,大家应该明白我们为什么要先写一个 BaseCardView 类  这里我们 HeaderCardView 继承 BaseCardView 并实现 BaseCardView 中的抽象方法

    贴出 header_card_view.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:layout_marginTop="20dp"
        android:orientation="vertical">
    
        <Button
            android:id="@+id/btn"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="HeaderView"
            android:textSize="20dp" />
    </LinearLayout>

    然后 MiddleCardView 和 FooterCardView 中的代码和这个类似,就不再一一贴代码,接下来我们在 FirstActivity 中进行组装

    FirstActivity 代码如下:

    public class FirstActivity extends AppCompatActivity {
        
        //引入需要组装的 CardView
        private HeaderCardView headerCardView;
        private MiddleCardView middleCardView;
        private FooterCardView footerCardView;
        
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            initView();
        }
    
        /**
         * 初始化 View
         */
        private void initView() {
            LinearLayout mContainer = findViewById(R.id.ll_container);
            addView(mContainer);
        }
    
        /**
         * 添加 View
         * @param mContainer
         */
    
        private void addView(LinearLayout mContainer) {
            addHerderCardView(mContainer);
            addMiddleCardView(mContainer);
            addFooterCardView(mContainer);
        }
    
        /**
         * 添加 HerderCardView
         * @param mContainer
         */
        private void addHerderCardView(LinearLayout mContainer) {
            if (headerCardView == null) {
                headerCardView = new HeaderCardView(this, mContainer);
                headerCardView.initViewWithData("你好");
                mContainer.addView(headerCardView.getView());
            }
        }
        
        /**
         * 添加 MiddleCardView
         * @param mContainer
         */
        private void addMiddleCardView(LinearLayout mContainer) {
            if (middleCardView == null) {
                middleCardView = new MiddleCardView(this, mContainer);
                mContainer.addView(middleCardView.getView());
            }
        }
        
        /**
         * 添加 FooterCardView
         * @param mContainer
         */
        private void addFooterCardView(LinearLayout mContainer) {
            if (footerCardView == null) {
                footerCardView = new FooterCardView(this, mContainer);
                mContainer.addView(footerCardView.getView());
            }
        }
    }

    对应 activity_first 中的代码如下:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout 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"
        android:orientation="vertical"
        tools:context=".FirstActivity">
    
        <LinearLayout
            android:id="@+id/ll_container"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical" />
    
    </LinearLayout>

    相信看到这里大家应该看明白了我们的实现思路,如果界面比较复杂我们就可以借用此思想来实现,把一个界面细化,通过小模块来实现  达到代码的复用和可维护。

    数据的传入,接下来我们来看数据如何传入:

    这里我们仍然用 HeaderCardView 来做演示 :

    public class HeaderCardView extends BaseCardView {
        
        private Button btn;
    
        public HeaderCardView(Context context, @NonNull ViewGroup root) {
            super(context, root);
        }
        
        @Override
        protected int onBindLayoutId() {
            return R.layout.header_card_view;
        }
    
        @Override
        protected void onViewCreated(View view) {
            btn = view.findViewById(R.id.btn);
        }
    
        public void initViewWithData(String data) {
            btn.setText(data);
        }
    }

    大家看到,其实是比较简单的  我们定义了 initViewWithData() 函数 用来传递数据 这里我们只简单的来传递一个 Sring 字符串,大家可以根据项目实际需要来传具体的值,接下来我们只需要在调用 HeaderCardView 的类中传递相应的值即可,例如我们在FirstActivity 中做一下演示:

    public class FirstActivity extends AppCompatActivity {
        
        private HeaderCardView headerCardView;
        private MiddleCardView middleCardView;
        private FooterCardView footerCardView;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            initView();
        }
        
        private void initView() {
            LinearLayout mContainer = findViewById(R.id.ll_container);
            addView(mContainer);
        }
        
        private void addView(LinearLayout mContainer) {
            addHerderCardView(mContainer);
            addMiddleCardView(mContainer);
            addFooterCardView(mContainer);
        }
    
        private void addHerderCardView(LinearLayout mContainer) {
            if (headerCardView == null) {
                headerCardView = new HeaderCardView(this, mContainer);
                headerCardView.initViewWithData("你好");
                mContainer.addView(headerCardView.getView());
            }
        }
        
        private void addMiddleCardView(LinearLayout mContainer) {
            if (middleCardView == null) {
                middleCardView = new MiddleCardView(this, mContainer);
                mContainer.addView(middleCardView.getView());
            }
        }
        
        private void addFooterCardView(LinearLayout mContainer) {
            if (footerCardView == null) {
                footerCardView = new FooterCardView(this, mContainer);
                mContainer.addView(footerCardView.getView());
            }
        }
    }

    运行程序如下:

     

           大家看到我们设置的值已经显示出来,例如我们在日常开发中如果两个界面都用到某一个模块 是不是我们很容易就能实现,只需在对应位置把我们的 CardView 使用 addView 加载进去就好,这里的例子虽然比较简单,但是提供了一种把复杂界面简单化的思想,大家如果在开发中遇到比较复杂的界面 可以借用此思想进行拆分,达到可维护以及可复用性,说到复用我们具体看下复用的方便性,这里我们创建 SecondActivity 如下:

    public class SecondActivity extends AppCompatActivity {
    
        private HeaderCardView headerCardView;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_second);
            initView();
        }
    
        private void initView() {
            LinearLayout mContainer = findViewById(R.id.ll_container);
            addView(mContainer);
        }
    
        private void addView(LinearLayout mContainer) {
            addHerderCardView(mContainer);
        }
        
        private void addHerderCardView(LinearLayout mContainer) {
            if (headerCardView == null) {
                headerCardView = new HeaderCardView(this, mContainer);
                mContainer.addView(headerCardView.getView());
            }
        }
    }

    这里我们对 HeaderCardView 进行了复用  是不是就显得非常方便,今天就分享到这里

    展开全文
  • 在我的应用程序中,我使用addView动态地向布局添加视图.添加的视图预先使用膨胀andorid:layout_width="match_parent"但是,在添加视图后使用parentView.addView(view, index);视图已添加,但不会填充父级的宽度我想这是...
  • @OverridepublicObjectinstantiateItem(Viewcontainer,intposition){container.addView(viewList.get(position));returnviewList.get(position);//TODOAuto-generatedmethodstub}@Overridepublicvoidde...
  • 有两个设计好的layout(xml文件)A和B,现要求将B作为A的子视图放在A的某处,这个功能通过addview来实现。下面我来介绍一下关于添加子视图的方法。1.构造两个xml文件2.LayoutInflater提到addview,首先要了解一下...
  • Fragment是Android honeycomb 3.0新增的概念,在Android——Fragment介绍、AndroidFragment使用、Android FragmentManageFragmentTransaction介绍中做了关于Fragment的详细介绍。这一片主要通过一个实例了解Fragment...
  • 先列出调用流程,让读者能有个大概的认知: windowmanager.addview() WindowManagerImpl.addview() WindowManagerGlobal.addview() ViewRootImpl.setView() WindowManagerImpl.addview() WindowManagerImpl.addView...
  • addView方法简介 在Android中,addView(ViewGroup view, index)在指定的index处添加一个view。可以利用排版View的 addView 函数,将动态产生的View 物件加入到排版View 中。 2、示例: (1)首先我们往布局文件中...
  • android - 在notifyDatasetChanged()之后,RecyclerView闪烁我有一个RecyclerView,它从API加载一些数据,包括一个图像URL和一些数据,我使用networkImageView来延迟加载图像。@Overridepublic void onResponse(List...
  • 这些方法里,Activity的setContentView,Dialog的setView,都是在控件生命周期执行过程中设置,这时view树还没有被构建,而ViewGroup的addView则往往是view树已经构建并且显示在窗口上之后被调用。要了解ViewGroup的...
  • LinearLayout.LayoutParams params = new android.widget.LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); params.width = 200; params.height = 200; view.setLayoutParams...
  • 我有以下带有LinearLayout的main.xml文件android:orientation="vertical"android:layout_width="fill_parent"android:layout_height="fill_parent"android:weightSum="1" android:id="@+id/llid">android:id="@+...
  • 记着在很久以前写Android的时候做一个在最上层悬浮的一个View非常容易,什么权限啊什么的根本没有那么多限制,,但今天试着写了一下发现处处碰壁,出现了各种各样的问题,后来在网上看了一些资料,发现现在在Android...
  • 我们看下布局加载的入口说明:本文讲的Activity为 不同于,翻源码的同学注意下~Activity->onCreate()-> setContentView();其中方法调用了 getWindow().setContentView(layoutResID);public void setContentView...
  • android因各大厂商自己定制Rom导致悬浮式通知栏在很多手机上显示不出来等各种问题,没办法,最后采取了使用WindowManager的方式来做。效果QQ图片20171123150323.png具体代码就帖了,网上很多介绍WindowManager使用的...
  • views.addView(views.getLayoutId(), newView); // Tell the AppWidgetManager to perform an update on the current App Widget appWidgetManager.updateAppWidget(appWidgetId, views); 有任何想法吗? 这就是我...
  • 场景:之前原生项目开发中,遇到了动态2级表格需求,最开始使用viewGroup的addview()方法,动态对表格内容进行添加。但发现动态添加时,会导致渲染速度十分缓慢,在请求获取到数据后,过了好几秒才渲染完成。 分析...
  • 我有一个针对平板电脑的ICS代码.我想动态地添加一个...这部分代码来自Android音乐应用程序的TouchInterceptor.java文件.mWindowParams = new WindowManager.LayoutParams();mWindowParams.gravity = Gravity...
  • baseLayout.addView(b); 在另一个视图下方重新定位视图代码片段: Buttons b = (Buttons) viewIndex; positioningLayout = new RelativeLayout.LayoutParams(b.getLayoutParams()); positioningLayout.addRule...
  • 基于 Android API 26 Platform 源码写作背景在上一篇探究Android View 绘制流程,Xml 文件到 View 对象的转换过程我们了解了setContentView(resId) 如何把 xml 文件转换成 Java 中的 View 对象。本篇文章在此基础上...
  • 本文主要讲述如何动态给UI界面...1. addView方法简介在Android 中,可以利用排版View的 addView 函数,将动态产生的View 物件加入到排版View 中。例子如下:Activity代码:public class helloWorld extends Activity...
  • } 那么就是到WindowManagerImpl类中找addView方法了 public void addView(View view, ViewGroup.LayoutParams params) { mGlobal.addView(view, params, mDisplay, mParentWindow); } 继续看这个mGlobal对象 public...
  • 目录image效果展示image代码展示class AnimMenuActivity : AppCompatActivity(){private var isOpen = false //菜单是否打开private var menuArray = ArrayList()override fun onCreate(savedInstanceState: Bundle?...
  • 不仅如此,在RecyclerView中动态addView,也会出现混乱的现象,如下图://RecyclerView中给RadioGroup动态添加RadioButtonRadioGroup rgEvaluate;for (EvaluateItem item : evaluateGroup.getItemLis...
  • 1、addView窗体泄漏问题:android.view.WindowLeakedandroid.view.WindowLeaked一般会发生在Activity与Dialog的显示。(1)dialog、PopupWindown窗体原因:我们知道Android的每一个Activity都有个WindowManager窗体...
  • Android开发中,我在一个视图中addView另一个布局视图(该视图通过inflate加载获得,其中root为null即没有附加parent视图),为什么还是会报错误:The specified child already has a parent. You must call ...
  • 正如pskink所说,你只能以编程方式将视图添加到ViewGroup.您可以添加到LinearLayout,例如:...layout.addView(new EditText(context));不过,这可能对你的场景没有帮助.要将图像放在另一个图像上,可以使用Rel...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 67,419
精华内容 26,967
关键字:

安卓addview