• 我先自来熟的唠嗑几句,终于大学毕业了,博客开通不久,遇到一些好的东西想分享出来,以后在项目中使用或者遇到的问题,我也会分享在博客里,既是对自己技术的一个记录总结,也希望有更多的IT大牛指点指点,或者爱...

    我先自来熟的唠嗑几句,终于大学毕业了,博客开通不久,遇到一些好的东西想分享出来,以后在项目中使用或者遇到的问题,我也会分享在博客里,既是对自己技术的一个记录总结,也希望有更多的IT大牛指点指点,或者爱技术的朋友一起讨论讨论。闲话不多说,切入正题。
    1.认识expandablelistview和它的adapter
    这里写图片描述
    先看图,我想很多刚接触安卓这个行业的,有时候会遇到图上的这种需求,拿到这种图,很多时候我们都是考虑用listview去写,用type标签的去判断哪一块显示什么,这里给大家介绍下expandablelistview实现这样一个界面的方便之处。
    首先我们来认识一下,expandablelistview又名扩展列表,顾名思义就是拥有可扩展的子级列表,允许有父级标签,外加自己子级的内容。其实它就相当于两个listview的嵌套,说白了就是listview扩展来的。
    认识了expandablelistview后,我们就知道它是有父级和子级列表,所以很自然的想到,添加内容进去肯定需要一个父级的集合,和子级集合。所以就可以先定义两个list集合:

     private List<String> groupArray;//定义父级列表
     private List<List<String>> itemArray;//定义子列表

    接下来我们去认识expandablelistview的adapter
    要将数据展示出来,或者进行个性化的定制是离不开BaseExpandableListAdapter这个adapter的,那么我们先了解一下这个adapter到底有哪些属性。

      @Override
        public int getGroupCount() {
            return groupArray.size();
        }
    
        @Override
        public int getChildrenCount(int i) {
            return itemArray.get(i).size();
        }
    
        @Override
        public Object getGroup(int i) {
            return getGroup(i);
        }
    
        @Override
        public Object getChild(int i, int i1) {
            return itemArray.get(i).get(i1);
        }
    
        @Override
        public long getGroupId(int i) {
            return i;
        }
    
        @Override
        public long getChildId(int i, int i1) {
            return i1;
        }
    
        @Override
        public boolean hasStableIds() {
            return false;
        }
    
        @Override
        public View getGroupView(int i, boolean b, View view, ViewGroup viewGroup) {
            view = View.inflate(context, R.layout.item_lte_relate_group,null);
            GroupHolder holder = new GroupHolder(view);
            holder.tvGroup.setText(groupArray.get(i));
            return view;
        }
    
        @Override
        public View getChildView(int i, int i1, boolean b, View view, ViewGroup viewGroup) {
           view = View.inflate(context,R.layout.item_lte_relate_child,null);
            ChildHolder holder = new ChildHolder(view);
            if (i != groupArray.size()-1){
                if (i1 == itemArray.get(i).size()-1){
                    holder.tvDivider.setVisibility(View.VISIBLE);
                }
            }
            holder.tvItem.setText(itemArray.get(i).get(i1));
            return view;
        }
    
        @Override
        public boolean isChildSelectable(int i, int i1) {
            return true;
        }
        class GroupHolder{
            private TextView tvGroup;
            public GroupHolder(View view) {
                tvGroup = (TextView) view.findViewById(R.id.tv_relate_group);
            }
        }

    可以看到BaseExpandableListAdapter的属性是很多的,但是别怕,我们一个一个的解读,解读完,我相信这个扩展列表对你来说就是小菜一碟了。

    getGroupCount()
    这个代表你要填进去的父级标签的数量,也就是之前定义好的groupArray的size。
    getChildrenCount(int i)
    再看这个,这个顾名思义是获取子级标签的数量,不过这里有个int i;往前面一想,之前定义的itemArray是一个包含集合的集合,所以这里意思很明确,就是填如第i个子级里面的元素集合itemArray.get(i).size()。
    getChild(int i, int i1)
    接下来看这个比较重要的方法,注意区分i和i1,i是表示第几个子级标签,而i1才是表示第i个子级标签下的第i1个元素。
    boolean hasStableIds()
    返回false是表示通过getviewid来判断getview,哪些需要刷新,起到局部刷新的作用。
    public View getGroupView()
    这个方法就和listview的getview一样,不过这里多了个group,所以这里是进行父级标签的初始化和赋值。
    public View getChildView()
    这个方法是进行子级标签的初始化和赋值。
    至此,对BaseExpandableListAdapter属性的已经介绍完毕,所以说,认真看看,其实这个控件也不难,而且很容易就上手了,不用进行listview过多的判断和操作,就能很容易实现扩展列表,达到多项展开的目的。当然有一点比较重要,mEpListView.setDivider这个属性,和mEpListView.setChildDivider都是设置分割线,要想实现父级和父级间有个灰色间隔,而子级间是一个细线那么上面这两种就不够用了。那么下边就给大家介绍我自己的方法。不说了,老司机要上核心代码了,口水都干了,各位看官且往下看:

     @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                 Bundle savedInstanceState) {
            View view=inflater.inflate(R.layout.fragment_lte_relate,container,false);
            mEpListView = (ExpandableListView) view.findViewById(R.id.lte_relate_ep);
            mEpListView.setGroupIndicator(null);//这个是去掉父级的箭头
    
            groupArray = new ArrayList<String>();//父级列表
            itemArray = new ArrayList<List<String>>();//子级列表
            List<String> array1 = new ArrayList<String>();//子级列表元素
            List<String> array2 = new ArrayList<String>();//子级列表元素
            List<String> array3 = new ArrayList<String>();//子级列表元素
    
                groupArray.add("关联基站");
                groupArray.add("关联RRU");
                groupArray.add("关联天线");
                array1.add("建邺区_爱达花园_宏达型");
    
                array2.add("OMC_3207.ENB_278528_0-64-0");
                array2.add("OMC_3207.ENB_278528_0-64-1");
                array2.add("OMC_3207.ENB_278528_0-64-2");
    
                array3.add("某某区天线1");
                array3.add("某某区天线2");
                array3.add("某某区天线3");
                itemArray.add(array1);
                itemArray.add(array2);
                itemArray.add(array3);
    
    
            //首次加载的时候展开所有项
            mEpListView.setAdapter(new FragmentRelateEpAdapter(groupArray,itemArray,getActivity()));
            for (int i = 0; i < groupArray.size(); i++) {
                mEpListView.expandGroup(i);
            }
            //点击不能收缩
            mEpListView.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() {
    
                @Override
                public boolean onGroupClick(ExpandableListView parent, View v,
                                            int groupPosition, long id) {
                    // TODO Auto-generated method stub
                    return true;
                }
            });
            return view;
        }

    BaseExpandableListAdapter的设置

    public class FragmentRelateEpAdapter extends BaseExpandableListAdapter {
        private List<String> groupArray;
        private List<List<String>> itemArray;
        private Context context;
        public FragmentRelateEpAdapter(List<String> groupArray, List<List<String>> itemArray,Context context) {
            this.groupArray = groupArray;
            this.itemArray = itemArray;
            this.context = context;
        }
    
        @Override
        public int getGroupCount() {
            return groupArray.size();
        }
    
        @Override
        public int getChildrenCount(int i) {
            return itemArray.get(i).size();
        }
    
        @Override
        public Object getGroup(int i) {
            return getGroup(i);
        }
    
        @Override
        public Object getChild(int i, int i1) {
            return itemArray.get(i).get(i1);
        }
    
        @Override
        public long getGroupId(int i) {
            return i;
        }
    
        @Override
        public long getChildId(int i, int i1) {
            return i1;
        }
    
        @Override
        public boolean hasStableIds() {
            return false;
        }
    
        @Override
        public View getGroupView(int i, boolean b, View view, ViewGroup viewGroup) {
            view = View.inflate(context, R.layout.item_lte_relate_group,null);
            GroupHolder holder = new GroupHolder(view);
            holder.tvGroup.setText(groupArray.get(i));
            return view;
        }
    
        @Override
        public View getChildView(int i, int i1, boolean b, View view, ViewGroup viewGroup) {
           view = View.inflate(context,R.layout.item_lte_relate_child,null);
            ChildHolder holder = new ChildHolder(view);
            if (i != groupArray.size()-1){
                if (i1 == itemArray.get(i).size()-1){
                    holder.tvDivider.setVisibility(View.VISIBLE);
                }
            }
            holder.tvItem.setText(itemArray.get(i).get(i1));
            return view;
        }
    
        @Override
        public boolean isChildSelectable(int i, int i1) {
            return true;
        }
        class GroupHolder{
            private TextView tvGroup;
            public GroupHolder(View view) {
                tvGroup = (TextView) view.findViewById(R.id.tv_relate_group);
            }
        }
        class ChildHolder{
            private TextView tvItem;
            private View tvDivider;
            public ChildHolder(View view) {
                tvItem = (TextView) view.findViewById(R.id.tv_relate_item);
                tvDivider =  view.findViewById(R.id.item_divider);
            }
        }
    }

    注意:childholder里面我是定义了两个Textview,一个是显示数据的,一个就是我之前说的,灰色的分割线了。根据位置的判断,进行显示和隐藏。最后贴上childholder xml代码

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#fff">
        <TextView
            android:id="@+id/tv_relate_item"
            android:paddingRight="15dp"
            android:layout_width="match_parent"
            android:layout_height="40dp"
            android:gravity="center_vertical"
            android:textSize="@dimen/mobileom_lte_networkoverview_title_size"
            android:paddingLeft="10dp"
            android:textColor="#666666"
            android:text="建邺区_爱达花园_宏站型"/>
        <ImageView
            android:layout_width="15dp"
            android:layout_height="15dp"
            android:layout_alignParentRight="true"
            android:layout_centerVertical="true"
            android:layout_marginRight="10dp"
            android:src="@drawable/ico_lte_next"/>
        <View
            android:id="@+id/item_divider"
            android:layout_width="match_parent"
            android:layout_height="8dp"
            android:background="@drawable/ep_group_divider"
            android:layout_below="@id/tv_relate_item"
            android:visibility="gone"/>
    
    
    </RelativeLayout>

    最终成功图
    希望大家有什么好的意见和建议提出来,一起共同进步,我还是很菜的,希望大牛不吝赐教哦。我继续板砖去了。

    展开全文
  • 此demo实现了列表ListView和可扩展列表ExpandableListView。 demo:下载地址 ListViewActivity: package fk.androiddemo_16; import android.app.ListActivity; import android.os.Bundle; import ...

          此demo实现了列表ListView和可扩展列表ExpandableListView。


    demo:下载地址


    ListViewActivity:

    package fk.androiddemo_16;
    
    import android.app.ListActivity;
    import android.os.Bundle;
    import android.view.View;
    import android.widget.AdapterView;
    import android.widget.ListView;
    import android.widget.SimpleAdapter;
    import android.widget.Toast;
    
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    //1,继承ListActivity
    //2,Activity布局文件中添加ListView控件
    //3,为列表创建布局文件
    public class MyListActivity extends ListActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_list);
    
            List<Map<String, String>> data = new ArrayList<>();//列表
            Map<String, String> map1= new HashMap<>();//列表项
            map1.put("name", "liming1.mp3");//项键,键值(项内容)
            Map<String, String> map2 = new HashMap<>();
            map2.put("name", "liming2.mp3");
            Map<String, String> map3 = new HashMap<>();
            map3.put("name", "liming3.mp3");
            data.add(map1);//添加第一项
            data.add(map2);//添加第二项
            data.add(map3);//添加第三项
    
            //创建适配器(Activity,列表,布局文件
            // 列表项的键,列表项在布局中的位置)
            SimpleAdapter adapter = new SimpleAdapter(this, data, R.layout.child,
                    new String[] { "name" }, new int[] { R.id.child });
            setListAdapter(adapter);//添加适配器显示列表
    
            //设置列表长按的监听函数来监听长按操作
            getListView().setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
                public boolean onItemLongClick(AdapterView parent, View view, int position, long id) {
                    if(id==0) Toast.makeText(MyListActivity.this, "Fuck Finger!!", Toast.LENGTH_LONG).show();
                    else if(id==1) Toast.makeText(MyListActivity.this, "Give me a try ?!", Toast.LENGTH_LONG).show();
                    else if(id==2) Toast.makeText(MyListActivity.this, "OH !! Come on , baby ..", Toast.LENGTH_LONG).show();
                    return true;
                }
            });
        }
    
        @Override
        //短点击列表item时会调用此函数
        protected void onListItemClick(ListView l, View v, int position, long id) {
            super.onListItemClick(l, v, position, id);
            //l为被点击的列表,然后根据position得到点击的item,然后强转HashMap,再取得对应键的值
            String ss=((HashMap<String,String>)l.getItemAtPosition(position)).get("name");//也可以用下面的方法得到Item内容
            //String ss=((TextView)v.findViewById(R.id.child)).getText().toString();
            System.out.println("Position:"+position+" ID:"+id+" Content:"+ss);
        }
    }

    ExpandableListViewActivity:

    package fk.androiddemo_16;
    
    import android.app.ExpandableListActivity;
    import android.os.Bundle;
    import android.view.View;
    import android.widget.AdapterView;
    import android.widget.ExpandableListView;
    import android.widget.SimpleExpandableListAdapter;
    import android.widget.TextView;
    
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    //1,继承ExpandableListActivity
    //2,Activity布局文件中添加ExpandableListView控件
    //3,分别为group和child列表创建布局文件
    public class MyExpendableListActivity extends ExpandableListActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_expendable_list);
    
            //存放组列表,每个组都要有一个对应的子列表,否则出错
            List<Map<String, String>> groups = new ArrayList<>();
            Map<String, String> group1 = new HashMap<>();
            group1.put("group", "group1");//键,组名
            Map<String, String> group2 = new HashMap<>();
            group2.put("group", "group2");
            groups.add(group1);//加入第一个组
            groups.add(group2);//加入第二个组
    
    
            //一个子列表
            List<Map<String, String>> child1 = new ArrayList<>();
            Map<String, String> child1Date1 = new HashMap<>();
            child1Date1.put("child", "child1Date1");
            Map<String, String> child1Date2 = new HashMap<>();
            child1Date2.put("child", "child1Date2");
            child1.add(child1Date1);//子列表第一项
            child1.add(child1Date2);//子列表第二项
    
            //一个子列表
            List<Map<String, String>> child2 = new ArrayList<>();
            Map<String, String> child2Date1 = new HashMap<>();
            child2Date1.put("child", "child2Date1");
            Map<String, String> child2Date2 = new HashMap<>();
            child2Date2.put("child", "child2Date2");
            child2.add(child2Date1);//子列表第一项
            child2.add(child2Date2);//子列表第二项
    
            //存放所有组的子列表
            List<List<Map<String, String>>> childs = new ArrayList<>();
            childs.add(child1);//第一个组的子列表
            childs.add(child2);//第二个组的子列表
    
            //创建适配器(Activity,组列表,组布局文件,组名键值对键,布局中组名显示位置
            // 子列表,子列表布局文件,子列表项键值对键,布局中子列表项内容显示位置)
            SimpleExpandableListAdapter adapter = new SimpleExpandableListAdapter(
                    this, groups, R.layout.group, new String[]{"group"}, new int[]{R.id.group},
                    childs, R.layout.child, new String[]{"child"}, new int[]{R.id.child});
            setListAdapter(adapter);//添加适配器,显示列表
    
            //设置列表长按的监听函数来监听长按操作
            getExpandableListView().setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
                public boolean onItemLongClick(AdapterView parent, View view, int position, long id) {
                    //这里的position会根据group展开与否而变化,所以没有意义
                    System.out.println("position="+position+" id="+id);
                    return true;
                }
            });
        }
    
        @Override
        //短点击列表项时调用
        public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) {
    
            System.out.println(((TextView) v.findViewById(R.id.child)).getText());
            System.out.println("groupPosition:"+groupPosition+" childPosition:"+childPosition+" id:"+id);
    
            return super.onChildClick(parent, v, groupPosition, childPosition, id);
        }
    }

    ListViewActivity布局:

    <?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: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=".MyListActivity">
    
        <ListView
            android:id="@id/android:list"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:drawSelectorOnTop="true" />
    
    </RelativeLayout>

    ExpandableListViewActivity布局:

    <?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: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=".MyExpendableListActivity">
    
        <ExpandableListView
            android:id="@id/android:list"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:drawSelectorOnTop="true" />
    
    </RelativeLayout>

    ListView和ExpandableListView的child条目布局:

    <?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">
    
        <TextView
            android:id="@+id/child"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:padding="10px"
            android:text="No Date"
            android:textSize="20sp" />
    
    </LinearLayout>

    ExpandableListView的group条目布局:

    <?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">
    
        <TextView
            android:id="@+id/group"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:paddingBottom="10px"
            android:paddingLeft="70px"
            android:paddingTop="10px"
            android:text="No Date"
            android:textSize="26sp" />
    
    </LinearLayout>

    运行截图:



    控制台输出结果:

    10-04 09:56:22.073 2794-2840/fk.androiddemo_16 D/OpenGLRenderer: endAllActiveAnimators on 0x7ffedc87d800 (RippleDrawable) with handle 0x7ffedbe326c0
    10-04 09:56:24.273 2794-2794/fk.androiddemo_16 I/System.out: Position:0 ID:0 Content:liming1.mp3
    10-04 09:56:25.948 2794-2794/fk.androiddemo_16 I/System.out: Position:1 ID:1 Content:liming2.mp3
    10-04 09:56:27.413 2794-2794/fk.androiddemo_16 I/System.out: Position:2 ID:2 Content:liming3.mp3
    10-04 09:56:43.984 2794-2840/fk.androiddemo_16 D/OpenGLRenderer: endAllActiveAnimators on 0x7ffedc87dc00 (RippleDrawable) with handle 0x7ffedba5c240
    10-04 09:56:50.848 2794-2794/fk.androiddemo_16 I/System.out: child1Date1
    10-04 09:56:50.848 2794-2794/fk.androiddemo_16 I/System.out: groupPosition:0 childPosition:0 id:0
    10-04 09:56:52.850 2794-2794/fk.androiddemo_16 I/System.out: child1Date2
    10-04 09:56:52.850 2794-2794/fk.androiddemo_16 I/System.out: groupPosition:0 childPosition:1 id:1
    10-04 09:56:57.696 2794-2794/fk.androiddemo_16 I/System.out: child2Date1
    10-04 09:56:57.696 2794-2794/fk.androiddemo_16 I/System.out: groupPosition:1 childPosition:0 id:0
    10-04 09:57:00.852 2794-2794/fk.androiddemo_16 I/System.out: child2Date2
    10-04 09:57:00.853 2794-2794/fk.androiddemo_16 I/System.out: groupPosition:1 childPosition:1 id:1





    展开全文
  • Android可收缩/扩展的TextView【1】 在一些应用中,比如腾讯的应用市场APP应用宝,关于某款应用的介绍文字,如果介绍文字过长,那么不是全部展现出来,而是显示三四行的开始部分(摘要),预知全部的内容,用户点击...
    

    Android可收缩/扩展的TextView【1】

    在一些应用中,比如腾讯的应用市场APP应用宝,关于某款应用的介绍文字,如果介绍文字过长,那么不是全部展现出来,而是显示三四行的开始部分(摘要),预知全部的内容,用户点击展开按钮即可查阅全部内容。
    这样的设计有一定的优越性,毕竟用户的时间有限,注意力和关注力也有限,在使用APP时候,用户需要在最短时间内尽可能快速浏览和查阅到更主要内容,而不是一大堆泛泛而谈的文字内容。
    在Android原生的TextView的基础上,我自己写了一个可收缩/扩展的TextView:PhilExpandableTextView。
    实现原理:核心是控制TextView的max lines。在TextView的初始化阶段但尚未绘制出View的时候,使用ViewTreeObserver,监听onPreDraw事件,获取TextView正常显示需要显示的总行数,但只给TextView设置最大运行的行数(小于总行数),从而造成TextView的收缩摘要效果,当用户通过按钮或其他方式扩展时候,把TextView的最大行数设置为正常显示完全的行数+1(+1是保持余量,避免不足)。
    最终,如图,图1是收缩状态:



    图2是当用户点击了Button按钮后展开后的状态:


    给出测试及全部源代码。


    测试的主Activity MainActivity.java:

    package zhangphil.textview;
    
    import android.app.Activity;
    import android.os.Bundle;
    import android.view.View;
    import android.widget.Button;
    
    public class MainActivity extends Activity {
    
    	private String test_str = "";
    	
    	@Override
    	protected void onCreate(Bundle savedInstanceState) {
    		super.onCreate(savedInstanceState);
    		setContentView(R.layout.activity_main);
    		
    		// 测试的字符串
    		for (int i = 0; i < 100; i++)
    				test_str = test_str + " " + i;
    
    		final PhilExpandableTextView text = (PhilExpandableTextView) findViewById(R.id.text);
    		text.setText(test_str);
    		
    		Button button = (Button) findViewById(R.id.button);
    		button.setOnClickListener(new View.OnClickListener() {
    			
    			@Override
    			public void onClick(View v) {
    				boolean b=text.getExpandableStatus();
    				b=!b;
    				text.setExpandable(b);
    			}
    		});
    	}
    }
    


    MainActivity.java需要的布局文件:

    <RelativeLayout 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"
        tools:context="zhangphil.textview.MainActivity" >
    
        <zhangphil.textview.PhilExpandableTextView
            android:id="@+id/text"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentTop="true"
            android:background="#03a9f4" />
    
        <Button
            android:id="@+id/button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_centerHorizontal="true"
            android:text="Button" />
    
    </RelativeLayout>


    核心的PhilExpandableTextView.java:

    package zhangphil.textview;
    
    import android.content.Context;
    import android.util.AttributeSet;
    import android.view.ViewTreeObserver;
    import android.widget.TextView;
    
    public class PhilExpandableTextView extends TextView {
    
    	// 最大的行,默认只显示3行
    	private final int MAX = 3;
    
    	// 如果完全伸展需要多少行?
    	private int lines;
    
    	private PhilExpandableTextView mPhilTextView;
    
    	// 标记当前TextView的展开/收缩状态
    	// true,已经展开
    	// false,以及收缩
    	private boolean expandableStatus = false;
    
    	public PhilExpandableTextView(Context context, AttributeSet attrs) {
    		super(context, attrs);
    
    		mPhilTextView = this;
    
    		init();
    	}
    
    	private void init() {
    
    		// ViewTreeObserver View观察者,在View即将绘制但还未绘制的时候执行的,在onDraw之前
    		final ViewTreeObserver mViewTreeObserver = this.getViewTreeObserver();
    
    		mViewTreeObserver.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
    
    			@Override
    			public boolean onPreDraw() {
    				// 避免重复监听
    				mPhilTextView.getViewTreeObserver().removeOnPreDrawListener(this);
    
    				lines = getLineCount();
    				// Log.d(this.getClass().getName(), lines+"");
    
    				return true;
    			}
    		});
    
    		setMaxLines(MAX);
    		
    		//setEllipsize(TextUtils.TruncateAt.END);
    	}
    
    	// 是否展开或者收缩,
    	// true,展开;
    	// false,不展开
    	public void setExpandable(boolean isExpand) {
    		if (isExpand) {
    			setMaxLines(lines + 1);
    		} else
    			setMaxLines(MAX);
    
    		expandableStatus = isExpand;
    	}
    
    	public boolean getExpandableStatus() {
    		return expandableStatus;
    	}
    }
    


    代码运行结果如图文中图示。

    展开全文
  • Kotlin扩展函数Extensions和RecyclerView实现简单列表

    在上一篇文章:使用Kotlin开发Android 创建工程与配置 主要是Kotlin相关的配置,这一篇主要是Kotlin Android Extensions

    喜欢用简书的朋友,可以浏览简书下的博客:使用Kotlin开发Android 扩展函数(Extensions)

    Kotlin Android Extensions

    我们在使用Java时,findViewById是比较麻烦的,通过控件的ID来查找控件,当然也有第三方框架ButterKnife,Dagger等来减少findViewById的使用,通过插件自动生成,但在使用Kotlin时,便不必如此。在app的Gradle下添加

    apply plugin: 'kotlin-android-extensions'
    

    Paste_Image.png

    使用扩展函数的好处

    在Kotlin官方文档中对ButterKnife类似的库是这样介绍

    Being libraries dependent on runtime, they require annotating fields for each View

    也就是说类似ButterKnife这类库,在运行时,需要对每一个控件进行注解。而对于Kotlin, 官方是这样介绍

    The Kotlin Android Extensions plugin allows us to obtain the same experience we have with some of these libraries, without having to add any extra code or shipping any additional runtime.

    Kotlin提供类似于这些库的相同体验,但不需要额外的代码和运行时间。我自己理解为减少findViewById的使用的同时,没有产生额外的代码,也不用在运行时对每个控件进行注解。

    第一个项目 木子饼干

    然后在xml文件里给TextView和Button添加一个Id,直接在MainActivity中

    import kotlinx.android.synthetic.main.activity_main.*
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        main_text.text = "木子饼干"
    
        main_button.setOnClickListener {
            val intent =Intent(this,RecyclerViewActivity::class.java)
            startActivity(intent)
        }
    
    }
    

    注意要导包import kotlinx.android.synthetic.main.activity_main.*,一般情况下Android Studio会自动添加这一句,格式一般为

    import kotlinx.android.synthetic.main..*

    为控件所在的布局文件,不同于Java ,在声明一个变量时,需要在变量前说明类型,Kotlin 一般使用val 和 var, var声明的变量是可变的,val 声明的变量是不可变的,同时也省略new关键字。运行如图

    Paste_Image.png

    在Adapter中的用法也类似,在布局文件中给控件添加ID,

    Paste_Image.png

    在Adapter中直接使用ID

    Paste_Image.png

    Android Studio也会导入相应的包,格式一般为

    import kotlinx.android.synthetic.main..view.*

    此处RecyclerVIew的布局文件为recycler_item ,因此这里为

    Paste_Image.png

    简单的列表展示Demo

    和新建Java类类似,新建Kotlin类只要在New的时候选择Kotlin File/Class

    Paste_Image.png

    在小弹框中选择Class,输入名称即可,我这里是RecyclerViewAdapter
    Paste_Image.png

    不同于平常的Adapter,Kotlin的Adapter可以在类名后直接加入调用时要传入的参数,相当于Java类中的Adapter的构造函数,Viewholder也不需要findViewById,也是直接使用ID,这里贴出代码

    class RecyclerViewAdapter(val context: Context, val list: List<String>) : RecyclerView.Adapter<RecyclerViewAdapter.RecyclerHolder>() {
    override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): RecyclerHolder {
    
        return RecyclerHolder(LayoutInflater.from(context).inflate(R.layout.recylcer_item, parent, false))
    }
    
    override fun getItemCount(): Int {
        return list.size
    }
    
    override fun onBindViewHolder(holder: RecyclerHolder, position: Int) {
        val s = list.get(position)
        holder.itemView.item_text.text = s
    
    }
    
    class RecyclerHolder(itemView: View?) : RecyclerView.ViewHolder(itemView) {
      }
    }
    

    在Activity中使用也相对简单,Kotlin 的for循环相对于java也有不同,不用声明 i变量,代码中的?意思我理解为否,?=也就是不等于空,这也是Kotlin相对于Java的优点,可以避免空指针,缺少?,AS会报错提示,或者可以再null后面添加!!,断言不为空。代码中..表示xx到xx,也就是一个范围

    class RecyclerViewActivity : AppCompatActivity() {
    
    var adapter:RecyclerViewAdapter ?= null
    //    var adapter:RecyclerViewAdapter  = null!!
    
    var list =ArrayList<String>()
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_recycler_view)
        initView()
    }
    
    fun initView() {
        for (i in 0 ..20){
            list.add("木子饼干" + i)
        }
        recyclerView.layoutManager = LinearLayoutManager(this)
        adapter = RecyclerViewAdapter(this,list)
        recyclerView.adapter = adapter
    
      }
    }
    

    运行如图
    Paste_Image.png

    代码地址:KotlinDemo

    展开全文
  • Android中的JS扩展有2中方式: 1.利用webkit提供的js扩展接口在 java层扩展,直接由app实现 优点:容易 缺点:跟app耦合,其他app不能使用该js扩展 2.利用npapi在cpp层扩展 优点:所有app都能共享该扩展 缺点...

    Android中的JS扩展有2中方式:

    1.利用webkit提供的js扩展接口在 java层扩展,直接由app实现
    优点:容易
    缺点:跟app耦合,其他app不能使用该js扩展
    2.利用npapi在cpp层扩展
    优点:所有app都能共享该扩展
    缺点:相对有难度

    引擎主要分为3大模块
    1.webkit                          平台相关代码,是对以下2模块的平台port封装
    2.webcore                       实现layout排版;渲染;当检测html中含有js脚本时交由jscore处理
    3.javascriptcore/v8         解析js脚本,并执行

    jscore跟webcore的交互 主要跟binding有关系。数据类型有map映射,一般的js扩展不涉及jscore的改动




    通过Android webview实现与javascript函数相互调用



      1. public  
      2. class WebViewDemo extends Activity {  
      3.     private WebView mWebView;  
      4.     private Handler mHandler = new Handler();  
      5.     public  
      6. void onCreate(Bundle icicle) {  
      7.         super.onCreate(icicle);  
      8.         setContentView(R.layout.webviewdemo);  
      9.         mWebView = (WebView) findViewById(R.id.webview);  
      10.         WebSettings webSettings = mWebView.getSettings();  
      11.         webSettings.setJavaScriptEnabled(true);  //webview支持javascript   
      12.         mWebView.addJavascriptInterface(new Object() {  //添加javascript可调用的接口   
      13.             public  
      14. void clickOnAndroid() {  
      15.                 mHandler.post(new Runnable() {  
      16.                     public void run() {  
      17.                         mWebView.loadUrl("javascript:wave()");  
      18.                     }  
      19.                 });  
      20.             }  
      21.         }, "demo");  
      22.         mWebView.loadUrl("file:///android_asset/demo.html");  //调用的网页  
      23.     }  
      24. }  
      1. </pre><pre name="code" class="java"><pre name="code" class="html">  
      1. demo.html:  
      1. <html>  
      2.         <script language="javascript">  
      3.                 function wave() { //准备在activity里调用的函数  
      4.                     document.getElementById("droid").src="android_waving.png";  
      5.                 }  
      6.         </script>  
      1. <body>  
      2.     <a onClick="window.demo.clickOnAndroid()"> //调用activity的clickOnAndroid()函数  
      3.                         <imgidimgid="droid"src="android_normal.png"/><br>Click me!  
      4.     </a>  
      5. </body>  
      6. l>  
    展开全文
  • 转载请标明出处: ... 本文出自:【张鸿洋的博客】 ...上周一我们发布了Android 百分比布局库(percent-support-lib) 解析与扩展中对percent-support这个库进行了解析和添加了PercentLinearLayout的支持。
  • android 获取文件的扩展名和去掉文件的扩展
  • Android现在可以让您的应用在辅助显示器上显示不同的内容程序,以有线或Wi-Fi将外接显示输出连接到用户设备上,显示独特的内容。要为辅助显示屏创建独特的内容,您需要扩展Presentation类,并实现onCreate()回调方法...
  • Android ExpandableLayout:一种可伸缩扩展的Layout 由于手机屏幕长度和尺寸的原因,在一些Android的开发场景中,某些特定的较为次要的二级操作选项(如安妮、播放、暂停、标签、提示、删除、新建、打开等等等...
  • 前段时间项目提了个新需求:我的红包需要做成二级列表的形式,实现的效果如下图所示: 支持的功能: 1.可自定义item的样式 2.自定义折叠效果 3.自定义展开方式 下面我说一下我在demo中的使用方式 1.demo中的...
  • 上个月接到项目重构的任务,让设计一种高扩展性,模块耦合更低的轻量级的架构。于是我根据app的业务和模块划分最终设计出了如下架构,该架构适合模块较多,模块中联系较低的app。根据近一个月的实战验证,确定了该...
  • 那么本篇文章是我们ListView系列三部曲的最后一篇,在这篇文章当中我们将对ListView进行功能扩展,让它能够以瀑布流的样式来显示数据。一直关注我博客的朋友们应该知道,其实在很早之前我就发布过一篇关于实现瀑布流...
  • Dagger 2应用于Android的完美扩展库 - dagger.android
  • 之前集成即时通讯(环信)的时候,...首先,在聊天界面添加一个发送扩展消息的MenuItem: 在ChatFragment类中定义一个常量,用来ItemId。 private static final int RECORDS = 20; 在registerExtendMenuIte()方法中
  • Android 表格控件-动态实现表格效果(内容、样式可扩展)说明:表格是很常用的控件,Android本身提供了TableLayout供布局实现,但本文介绍另外一种思路,用动态布局的方式实现,这种方式更灵活,内容、样式能高度...
  • 在某些android开发群里,看到有些新手问怎么实现QQ好友列表,其实网上一搜挺多的。接触Android,也才一年的时间,大部分时间花在工作上(解bug。。。),界面上开发很少参与。自己维护的系统应用里,有个...
  • CSDN上有篇Android滚轮时间选择控件(可扩展自定义),阅读量很高,看来大家对这块的需要还是挺大的。版本迭代开发自测完,等待测试提bug。就抽空把项目需求,自己自定义的一个控件分享给需要的人。里面可以学习到...
  • 最近在做广电项目,要求...android本身应用层提供了扩展方法,但是这可恶的规范导致应用层根本不可行,只好在webkit引擎里面做。。。 android 上编写 浏览器插件有三种方式, 1. app 层,通过android fram
1 2 3 4 5 ... 20
收藏数 185,753
精华内容 74,301