<问>Android问题集锦之控件类

一、EditText:

1、EditText自动换行的问题:

在xml布局中,设置EditText的相关属性:

    android:inputType="textMultiLine"  

亲测此方法可行
备注:(未测试)

其他文章中说可以通过如下方法:

    editText.setSingleLine(false);    //改变默认的单行模式  
    editText.setHorizontallyScrolling(false);  //水平滚动设置为False 

或设置属性:

    android:singleLine="false"  
    android:scrollHorizontally="false" 

二、获取view的可视区域:

    Rect rect = new Rect();
    parentView.getHitRect(rect);
    //子控件是否在可视范围内(至少有一个像素在可视范围内)
    boolean isInRect = childView.getLocalVisibleRect(scrollRect)

三、RecyclerView相关问题

1、ScrollView(RecyclerView[parent] )嵌套RecyclerView[childern]的问题:

原文链接:https://www.cnblogs.com/xgjblog/p/8260061.html
问题说明:进入页面自动跳转到RecyclerView[childern]上,页面会自动滚动

场景描述:如帖子列表中,每个条目会有一个图片列表,帖子列表和图片列表都用的是RecyclerView,当展示帖子列表时,若第一条没有图片的时候,会自动滚动到第二条的照片列表处。

原因猜测:可能是条目中的RecyclerView[childern] 自动获得了焦点才导致滚动的

解决方案:
A、去除条目中Recyclerview的焦点

recyclerview.setFocusableInTouchMode(false);
recyclerview.requestFocus();

B、设置第一个条目(或顶部)某一控件获取焦点
如第一个条目(或顶部)有一个textview,可设置为:

textview.setFocusableInTouchMode(true); 
textview.requestFocus(); 

C、设置根布局的属性

android:descendantFocusability="blocksDescendants"

android:descendantFocusability 有三种值:

  • beforeDescendants:viewgroup会优先其子类控件而获取到焦点
  • afterDescendants:viewgroup只有当其子类控件不需要获取焦点时才获取焦点
  • blocksDescendants:viewgroup会覆盖子类控件而直接获得焦点
    这种方法,会造成页面中Editext焦点被抢导致无法输入,需要用到B方法。

原理:
android:focusableInTouchMode为什么能解决ScrollView自动滚动的原理分析
ViewGroup#addView —> addViewInner —> requestChildFocus

        final boolean childHasFocus = child.hasFocus();
        if (childHasFocus) {
            requestChildFocus(child, child.findFocus());
        }

requestChildFocus责任链模式,会调用到ScrollView#requestChidlFocus,在ScrollView中重写了requestChidlFocus方法:

@Override
public void requestChildFocus(View child, View focused) {
    if (!mIsLayoutDirty) {
        scrollToChild(focused);
    } else {  //走这里,下面重写了requestLayout方法设定了true
        mChildToScrollTo = focused;
    }
    super.requestChildFocus(child, focused);
}

@Override
public void requestLayout() {
    mIsLayoutDirty = true;
    super.requestLayout();
}

ViewGroup#requestChildFocus中对descendantFocusability属性进行了判断,为blocksDescendants时直接返回,不执行mParent.requestChildFocus方法
所以可以解决自动滑动的问题
如不设置这个属性为blocksDescendants,则会执行mParent.requestChildFocus方法,即调用scheduleTraversals();,进行view树的重绘(measure、layout、draw等)

ScrollView滑动到获取焦点的子View的位置
ScrollView#onLayout方法
执行了scrollToChild(mChildToScrollTo);
requestChildFocus中,对mChildToScrollTo进行了赋值,见上面

2、RecyclerView滚动动画

参考:https://blog.csdn.net/limiao2143/article/details/51211654
如果需要列表滚动到指定位置,可以使用如下代码:

scrollToPosition(position)

但这行代码,显示会比较生硬,很不平滑,如果需要有动画效果,需要使用如下代码:

    val llm = LinearLayoutManager(mContext)
    val smoothScroller= object : LinearSmoothScroller(mContext) {
        override fun getVerticalSnapPreference(): Int {
            return SNAP_TO_END
        }
        override fun calculateTimeForScrolling(dx: Int): Int {
            return super.calculateTimeForScrolling(placeDx)
        }
    }

    smoothScroller.targetPosition = selectPosition  //设置目标位置
    llm.startSmoothScroll(smoothScroller)

问题说明:如果列表数据很多,滑动的位置相距越大,滑动得越慢,这就导致会等待很长时间。

解决方案:重写smoothScrollToPosition的滚动时间

    val smoothScroller= object : LinearSmoothScroller(mContext) {
        override fun getVerticalSnapPreference(): Int {
            return SNAP_TO_END
        }

        //此函数计算滚动dx的距离需要多久
        override fun calculateTimeForScrolling(dx: Int): Int {
            //return super.calculateTimeForScrolling(placeDx)
            return 300;  //或者通过dx 来动态计算
        }
    }

四、嵌套相关问题:

1、解决SwipeRefreshLayout与其嵌套控件的冲突问题

代码:

import android.content.Context;
import android.support.v4.widget.SwipeRefreshLayout;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.ListView;

import com.xs.lib.core.util.MyLog;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

import cn.daoyibigu.R;


/**
 * 解决SwipeRefreshLayout与其嵌套控件的冲突
 * @author hyk
 *
 */
public class MySwipeRefreshLayout extends SwipeRefreshLayout {

    private ListView mListView;
    private OnLoadListener mOnLoadListener;

    // private float firstTouchY;
    // private float lastTouchY;

    private float startY;
    private float startX;
    // 记录viewPager是否拖拽的标记
    private boolean mIsVpDragger;
    private int mTouchSlop;

    private boolean isLoading = false;

    private boolean scrollFlag = false;// 标记是否滑动

    public MySwipeRefreshLayout(Context context) {
        this(context, null);
        init(context);
    }

    public MySwipeRefreshLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    // 四种颜色变换
    private void init(Context context) {
        this.setColorSchemeResources(R.color.google_blue, R.color.google_green, R.color.google_red,
                R.color.google_yellow);
        mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
    }

    // set the child view of RefreshLayout,ListView
    public void setChildView(ListView mListView) {
        this.mListView = mListView;
        this.mListView.setOnScrollListener(new OnScrollListener() {

            @Override
            public void onScrollStateChanged(AbsListView listView, int scrollState) {
                switch (scrollState) {
                    // 当不滚动时
                    case OnScrollListener.SCROLL_STATE_IDLE:// 是当屏幕停止滚动时
                        scrollFlag = false;
                        break;
                    case OnScrollListener.SCROLL_STATE_TOUCH_SCROLL:// 滚动时
                        scrollFlag = true;
                        break;
                    case OnScrollListener.SCROLL_STATE_FLING:// 是当用户由于之前划动屏幕并抬起手指,屏幕产生惯性滑动时
                        scrollFlag = true;
                        break;
                }
            }

            @Override
            public void onScroll(AbsListView listView, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
                if (null != mOnLoadListener) {
                    if (!isLoading && visibleItemCount > 0 && (firstVisibleItem + visibleItemCount == totalItemCount)) {
                        setLoading(true);
                    }
                }
            }
        });
    }

    public void setLoading(boolean loading) {
        if (mListView == null)
            return;
        isLoading = loading;
        if (loading) {
            if (isRefreshing()) {
                setRefreshing(false);
            }
            mListView.setSelection(mListView.getAdapter().getCount() - 1);
            mOnLoadListener.onLoad(loading);
        }
        // else {
        // firstTouchY = 0;
        // lastTouchY = 0;
        // }
    }

    /**
     * 自动刷新
     */
    public void autoRefresh() {
        try {
            Field mCircleView = SwipeRefreshLayout.class.getDeclaredField("mCircleView");
            mCircleView.setAccessible(true);
            View progress = (View) mCircleView.get(this);
            progress.setVisibility(VISIBLE);

            Method setRefreshing = SwipeRefreshLayout.class.getDeclaredMethod("setRefreshing", boolean.class,
                    boolean.class);
            setRefreshing.setAccessible(true);
            setRefreshing.invoke(this, true, true);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void setOnLoadListener(OnLoadListener loadListener) {
        mOnLoadListener = loadListener;
    }

    public void removeOnLoadListener() {
        mOnLoadListener = null;
    }

    public interface OnLoadListener {
        void onLoad(boolean isStart);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        int action = ev.getAction();
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                // 记录手指按下的位置
                startY = ev.getY();
                startX = ev.getX();
                // 初始化标记
                mIsVpDragger = false;
                break;
            case MotionEvent.ACTION_MOVE:
                // 如果viewpager正在拖拽中,那么不拦截它的事件,直接return false;
                if(mIsVpDragger) {
                    return false;
                }

                // 获取当前手指位置
                float endY = ev.getY();
                float endX = ev.getX();
                float distanceX = Math.abs(endX - startX);
                float distanceY = Math.abs(endY - startY);
                // 如果X轴位移大于Y轴位移,那么将事件交给viewPager处理。
                if(distanceX > mTouchSlop && distanceX > distanceY) {
                    mIsVpDragger = true;
                    return false;
                }
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                // 初始化标记
                mIsVpDragger = false;
                break;
        }
        // 如果是Y轴位移大于X轴,事件交给swipeRefreshLayout处理。
        return super.onInterceptTouchEvent(ev);
    }

}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,794评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,050评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,587评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,861评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,901评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,898评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,832评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,617评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,077评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,349评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,483评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,199评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,824评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,442评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,632评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,474评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,393评论 2 352

推荐阅读更多精彩内容